home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Pascal / Applications / TCPExample / PNL Libraries / MyTransport.p < prev    next >
Text File  |  1997-06-18  |  78KB  |  2,925 lines

  1. unit MyTransport;
  2.  
  3. interface
  4.  
  5.     uses
  6.         Types, OpenTransport, TCPTypes, TCPUtils;
  7.     
  8.     var
  9.         have_OT:Boolean;
  10.  
  11.     const
  12.         couldNotGetRequestedPortErr = -900099;
  13.             
  14.     const
  15.         kMyStreamClosingErr = connectionClosingErr;
  16.     
  17.     type
  18.         TransportDeferredTaskCookie = longint;
  19.         TransportDeferredTaskProcPtr = ProcPtr; { procedure(arg:Ptr) }
  20.         TransportRef = ^integer;
  21.         TransportUDPRef = ^Point;
  22.     
  23.     type
  24.         IPAddrArray = array[1..1000] of ipAddr;
  25.         IPAddrArrayPtr = ^IPAddrArray;
  26.  
  27.     type
  28.         TransportPingResults = record
  29.                 remotehost: ipAddr;
  30.                 data: Ptr;
  31.                 datasize: longint;
  32.                 timetaken: longint; { time taken in microseconds }
  33.             end;
  34.             
  35.     type
  36.         MemoryReleasedProc = procedure (tref: TransportRef; result: OTResult; cookie: univ Ptr);
  37.         TransitionNotifierProc = procedure ( up: boolean );
  38.             { link comes up, OT/MT is initialized, you are called ith true, 
  39.                 link goes down or program finishes, you are called with false, OT/MT is released }
  40.  
  41.     var
  42.         hack_MemoryReleasedProc: MemoryReleasedProc;
  43.         transport_system_is_alive: Boolean;
  44. { * means Interupt-safe }
  45.  
  46.     procedure TransportInstallTransitionNotifier( notifier: TransitionNotifierProc ); { Can call this before Startup() }
  47.     
  48.     procedure StartupTransport;
  49.     procedure ConfigureTransport(allow_OT: Boolean);
  50.     
  51.     function OpenTransportSystem:OSStatus;
  52.     procedure CloseTransportSystem;
  53.  
  54.     function TransportListen(var token:Ptr; localport:ipPort; listeners:integer; buffer_size:longint):OSStatus;
  55.     function TransportGetListenerConnection(token:Ptr; var tref:TransportRef):OSStatus;
  56.     procedure TransportDestroyListener(var token:Ptr);
  57.  
  58.     function TransportOpenActiveConnection(var tref:TransportRef; dest:Str255; localport:ipPort; buffer_size:longint): OSStatus;
  59.     function TransportOpenPassiveConnection(var tref:TransportRef; var localport:ipPort; buffer_size:longint): OSStatus;
  60.     procedure TransportGetOpenResult(tref:TransportRef; var result: OSStatus); { * }
  61.     
  62.     procedure TransportDestroy(var tref:TransportRef);
  63.  
  64.     function TransportGetConnectionState (tref:TransportRef): TCPStateType;
  65.     function TransportGetConnectionStateInteruptSafe (tref:TransportRef): TCPStateType; { * }
  66.         { Note: May not change until idle time }
  67.     function TransportGetPorts(tref:TransportRef; var localip: ipAddr; var localport: ipPort; var remoteip: ipAddr; var remoteport: ipPort): OSStatus;
  68.     procedure TransportSendClose(tref:TransportRef);
  69.  
  70.     function TransportHandleTransfers(tref:TransportRef): OSStatus;
  71.  
  72.     function TransportHandleReceives(tref:TransportRef): OSStatus;
  73.     function TransportReceive(tref:TransportRef; buf: Ptr; len:longint; var count:longint): OSStatus;
  74.     function TransportCharsAvailable(tref:TransportRef): longint;
  75.     function TransferPeekCharsAvailable(tref:TransportRef; const look: Str255): longint;
  76.  
  77.     function TransportHandleSends(tref:TransportRef): OSStatus;
  78.     function TransportSend(tref:TransportRef; buf: Ptr; len:longint): OSStatus;
  79.     function TransportSendQueued(tref:TransportRef): longint;
  80.     
  81.     procedure TransportLowGetStreamPtr(tref:TransportRef; var stream: StreamPtr);
  82.     procedure TransportLowGetEndpointRef(tref:TransportRef; var ep: EndpointRef);
  83.     function TransportLowSetOTAckSends(tref:TransportRef; handler: MemoryReleasedProc): OSStatus;
  84.     
  85.     function TransportGetMyIPAddr(var ip:ipAddr): OSStatus;
  86.     
  87.     function TransportCreateDeferredTask(proc: OTProcessProcPtr; arg: UNIV Ptr): TransportDeferredTaskCookie;
  88.     procedure ScheduleDeferredTask(cookie:TransportDeferredTaskCookie); { * }
  89.     procedure DestroyDeferredTaskCookie(cookie:TransportDeferredTaskCookie);
  90.  
  91.     procedure TransportEnterInterrupt;
  92.     procedure TransportLeaveInterrupt;
  93.     
  94.     function TransportUDPOpenPort(var tref: TransportUDPRef; var localport: ipPort; buffer_size:longint): OSStatus;
  95.     procedure TransportUDPDestroy (var tref: TransportUDPRef);
  96.     function TransportUDPDatagramsAvailable (tref: TransportUDPRef): longint;
  97.     function TransportUDPRead (tref: TransportUDPRef; var remoteip: longint; var remoteport: ipPort;
  98.                                     var datap: Ptr; var datalen: integer): OSStatus;
  99.     function TransportUDPReturnBuffer (tref: TransportUDPRef; datap: Ptr): OSStatus;
  100.     function TransportUDPWrite (tref: TransportUDPRef; remoteip: longint; remoteport: ipPort;
  101.                                     datap: Ptr; datalen: integer; checksum: boolean): OSStatus;
  102.     
  103.     function TransportIPSendPing (remotehost: ipAddr; timeout: integer; datap: Ptr; datalen: integer; var token: Ptr): OSStatus;
  104.     procedure TransportGetIPSendPingResult( var token: Ptr; var result: OSStatus; var results: TransportPingResults );
  105.     procedure TransportDisposeIPSendPingResult( var results: TransportPingResults ); { call if TransportGetIPSendPingResult result = noErr to dispose data }
  106.     procedure TransportAbortIPSendPing( var token: Ptr );
  107.     
  108.     function TransportNameToAddr(name: Str255; var token: Ptr): OSStatus;
  109.     procedure TransportGetNameToAddrResult(var token: Ptr; var result: OSStatus; name:StringPtr; addrs:IPAddrArrayPtr; len:integer); { * }
  110.  
  111.     function TransportAddrToName(addr: ipAddr; var token: Ptr): OSStatus;
  112.     procedure TransportGetAddrToNameResult(var token: Ptr; var result: OSStatus; var name:Str255); { * }
  113.  
  114.     procedure TransportAbortDNR(var token: Ptr);
  115.  
  116.     procedure IdleTransport;
  117.  
  118. implementation
  119.  
  120.     uses
  121.         Events, TextUtils, Processes, OSUtils,Memory, Timer, Errors, Memory, 
  122.         OpenTptInternet, GestaltEqu, Devices, CodeFragments, MixedMode, MyLowLevel, 
  123.         MyCStrings, MyAssertions, DNR, MyStrings, MyMathUtils, MyGrowZones, MyTypes, 
  124.         MyUtils, MyMemory, MyCallProc, PreserveA5, MyStartup, MyLookFreeOT;
  125.         
  126.     const
  127.         use_OT_tasks = false;
  128.     
  129. {$ifc do_debug}
  130.     var
  131.         startup_check: integer;
  132. {$endc}
  133.  
  134.     type
  135.         TransitionInfo = record
  136.                 proc: TransitionNotifierProc;
  137.                 system: Boolean;
  138.             end;
  139.     const
  140.         max_transition_notifiers = 20;
  141.     var
  142.         transition_notifier_count: longint; { relies on Pascal to init this to zero at startup }
  143.         transitions: array[1..max_transition_notifiers] of TransitionInfo;
  144.         
  145.     type
  146.         TransportUDPRecord = record
  147.             case boolean of
  148.             false:(
  149.                 stream: StreamPtr;
  150.                 stream_buffer: Ptr;
  151.                 outstanding_packets: longint;
  152.             )
  153.             true:(
  154.                 ep: EndpointRef;
  155.                 packets_available: boolean;
  156.             )
  157.         end;
  158.         TransportUDPRecordPtr = ^TransportUDPRecord;
  159.         
  160.     type
  161.         TransportRecordPtr = ^TransportRecord;
  162.         TransportRecord = record
  163.             next: TransportRecordPtr;
  164.             input_handle: Handle;
  165.             max_input_handle_size: longint;
  166.             output_handle: Handle;
  167.             sending_handle: Handle;
  168.             send_error, receive_error: OSStatus;
  169.             open_result: OSStatus;
  170.             started_opening: Boolean;
  171.             handle_receives, handle_sends: Boolean;
  172.             do_send_close: Boolean;
  173.             case boolean of
  174.             false:(
  175.                 remote_port:ipPort;
  176.                 local_port:ipPort;
  177.                 stream:StreamPtr;
  178.                 stream_buffer:Ptr;
  179.                 open_cb, close_cb, send_cb:TCPControlBlock;
  180.                 send_wds: wdsType;
  181.                 dnr_token:Ptr;
  182.                 tstate:TCPStateType;
  183.             )
  184.             true:(
  185.                 ep: EndpointRef;
  186.                 rcvCall, sndCall: TCall;
  187.                 rcvsin: InetAddress;
  188.                 sndsin: DNSAddress;
  189.                 waiting_for_connect: Boolean;
  190.                 connect_received: Boolean;
  191.                 accept_received: Boolean;
  192.                 passcon_received: Boolean;
  193.                 wake_process:ProcessSerialNumber;
  194.                 disconnect_received: Boolean;
  195.                 connect_result:OSStatus;
  196.                 accept_result:OSStatus;
  197.                 passcon_result:OSStatus;
  198.                 MemoryReleasedHandler: MemoryReleasedProc;
  199.             )
  200.         end;
  201.  
  202.     type
  203.         MyDeferredTask = record
  204.             dt:DeferredTask;
  205.             fired:Boolean;
  206.             completion:UniversalProcPtr;
  207.             real_arg:longint;
  208.         end;
  209.         MyDeferredTaskPtr = ^MyDeferredTask;
  210.     
  211.     type
  212.         XInetHostInfo = record
  213.             host:InetHostInfo;
  214.             result:OSStatus;
  215.         end;
  216.         XInetHostInfoPtr = ^XInetHostInfo;
  217.         TDNRRecordPtr = ^TDNRRecord;
  218.         TDNRRecord = record
  219.             next:TDNRRecordPtr;
  220.             kind: (TK_NameToAddr, TK_AddrToName);
  221.             dead: Boolean;
  222.             case boolean of
  223.                 true:(
  224.                     dr:DNRRecord;
  225.                     canonical_name: Str255;
  226.                 );
  227.                 false:(
  228.                     xhost:XInetHostInfo; { Warning InetHostInfo must *start* with an InetDomainName! }
  229.                 );
  230.         end;
  231.     
  232.     const
  233. {        kReopenInternetServices = -91234598;}
  234.         idle_space_size = 32768;
  235.         max_reopen_frequency = 10 * second_in_ticks;
  236.         kOTVersion111 = $01118000;
  237.         kOTTILISTENVersion = kOTVersion111;
  238.     var
  239.         transports:QHdr;
  240.         gMyDeferredTaskHandlerProc : UniversalProcPtr;
  241.         is_ref:InetSvcRef;
  242.         is_result: OTResult;
  243.         dnrs:QHdr;
  244.         idle_space: Ptr;        
  245.         tcp_open_status: OSStatus;
  246.         last_reopen_time: longint;
  247.         calling_notifiers: Boolean;
  248.         ot_version: longint;
  249.         
  250.     procedure OTAbortAllDNRs; forward;
  251.  
  252.     procedure CallTransitionNotifiers( up: Boolean );
  253.         var
  254.             i: integer;
  255.             proc: TransitionNotifierProc;
  256.             saved_calling_notifiers: Boolean;
  257.     begin
  258.         saved_calling_notifiers := calling_notifiers;
  259.         calling_notifiers := true;
  260.         for i := 1 to transition_notifier_count do begin
  261.             if transitions[i].system = up then begin
  262.                 proc := transitions[i].proc;
  263.                 proc(up);
  264.             end;
  265.         end;
  266.         for i := 1 to transition_notifier_count do begin
  267.             if transitions[i].system <> up then begin
  268.                 proc := transitions[i].proc;
  269.                 proc(up);
  270.             end;
  271.         end;
  272.         calling_notifiers := saved_calling_notifiers;
  273.     end;
  274.         
  275.     procedure InstallTransitionNotifier( notifier: TransitionNotifierProc; system: Boolean );
  276.     begin
  277.         Assert( transition_notifier_count < max_transition_notifiers );
  278.         Inc(transition_notifier_count);
  279.         transitions[transition_notifier_count].proc := notifier;
  280.         transitions[transition_notifier_count].system := system;
  281.     end;
  282.     
  283.     procedure TransportInstallTransitionNotifier( notifier: TransitionNotifierProc );
  284.     begin
  285.         InstallTransitionNotifier( notifier, false );
  286.     end;
  287.     
  288.     function TransportSystemIsAlive: OSStatus;
  289.         var
  290.             err: OSStatus;
  291.             cb: IPControlBlock;
  292.             info:InetInterfaceInfo;
  293.     begin
  294.         err := tcp_open_status;
  295.         if err = noErr then begin
  296.             if have_OT then begin
  297.                 err := OTInetGetInterfaceInfo(info, 0);
  298.             end else begin
  299.                 MZero(@cb, SizeOf(cb));
  300.                 cb.ioCRefNum := mactcp_driver_refnum;
  301.                 cb.csCode := TCPcsGetMyIP;
  302.                 err := PBControlSync(@cb);
  303.             end;
  304.         end;
  305.         TransportSystemIsAlive := err;
  306.     end;
  307.     
  308.     procedure MCloseProvider( var ref: ProviderRef );
  309.         var
  310.             junk: OSErr;
  311.     begin
  312.         Assert( ref <> nil );
  313.         junk := OTCloseProvider( ref );
  314.         ref := nil;
  315.         Assert( junk = noErr );
  316.     end;
  317.     
  318.     procedure InternetServicesHandler(context:Ptr; event: OTEventCode; result: OTResult; cookie: XInetHostInfoPtr);
  319.     begin
  320. {$unused(context)}
  321.         case event of
  322.             T_OPENCOMPLETE: begin
  323.                 is_result := result;
  324.                 if result = noErr then begin
  325.                     is_ref := InetSvcRef(cookie);
  326.                 end;
  327.             end;
  328.             T_DNRSTRINGTOADDRCOMPLETE, T_DNRADDRTONAMECOMPLETE: begin
  329.                 cookie^.result := result;
  330.             end;
  331.             kOTProviderIsClosed, kOTProviderWillClose: begin
  332.                 if is_ref <> nil then begin
  333.                     MCloseProvider( is_ref );
  334.                     is_result := -900014;
  335.                 end;
  336.                 OTAbortAllDNRs;
  337.             end;
  338.             otherwise
  339.                 ;
  340.         end;
  341.     end;
  342.  
  343.     procedure InternetServicesNotifier( up: Boolean );
  344.         var
  345.             err: OSErr;
  346.             tmp: EndpointRef;
  347.     begin
  348.         if up then begin
  349.             is_ref := nil;
  350.             is_result := inProgress;
  351.             err := OTAsyncOpenInternetServices(OTConfigurationPtr(kDefaultInternetServicesPath), 0, @InternetServicesHandler,nil);
  352.             { WARNING: OTAsyncOpenInternetServices may have already completed }
  353.             if err <> noErr then begin
  354.                 is_result := err;
  355.             end;    
  356.         end else begin
  357.             OTAbortAllDNRs;
  358.             if (is_ref <> nil) then begin
  359.                 tmp := is_ref;
  360.                 is_ref := nil;
  361.                 MCloseProvider( tmp );
  362.             end;
  363.             if (is_result = noErr) or (is_result = inProgress) then begin
  364.                 is_result := -900015;
  365.             end;
  366.         end;
  367.     end;
  368.     
  369.     function WaitForInternetServices: OSStatus;
  370.     begin
  371.         while is_result = inProgress do begin
  372.             OTIdle;
  373.         end;
  374.         WaitForInternetServices := is_result;
  375.     end;
  376.     
  377.     function ValidDNR(token: Ptr): Boolean;
  378.         var
  379.             this:TDNRRecordPtr;
  380.     begin
  381.         ValidDNR := false;
  382.         this := TDNRRecordPtr(dnrs.qHead);
  383.         while this <> nil do begin
  384.             if Ptr(this) = token then begin
  385.                 ValidDNR := true;
  386.                 leave;
  387.             end;
  388.             this := this^.next;
  389.         end;
  390.     end;
  391.     
  392.     function TransportNameToAddr(name: Str255; var token: Ptr): OSStatus;
  393.         var
  394.             err: OSStatus;
  395.             tdrp:TDNRRecordPtr;
  396.     begin
  397.         tdrp := nil;
  398.         err := OpenTransportSystem;
  399.         if err = noErr then begin
  400.             err := MNewPtr(tdrp, SizeOf(TDNRRecord));
  401.         end;
  402.         if err = noErr then begin
  403.             tdrp^.kind := TK_NameToAddr;
  404.             tdrp^.dead := false;
  405.             if have_OT then begin
  406.                 tdrp^.xhost.result := inProgress;
  407.                 P2C(@name);
  408.                 err := WaitForInternetServices;
  409.                 if err = noErr then begin
  410.                     err := OTInetStringToAddress(is_ref, @name, tdrp^.xhost.host);
  411.                 end;
  412.             end else begin
  413.                 tdrp^.canonical_name := name;
  414.                 DNRNameToAddr(name, @tdrp^.dr, nil);
  415.                 err := noErr;
  416.             end;
  417.         end;
  418.         if err = noErr then begin
  419.             Enqueue(QElemPtr(tdrp),@dnrs);
  420.         end else begin
  421.             MDisposePtr(tdrp);
  422.         end;
  423.         token := Ptr(tdrp);
  424.         TransportNameToAddr := err;
  425.     end;
  426.     
  427.     procedure TransportGetNameToAddrResult(var token: Ptr; var result: OSStatus; name:StringPtr; addrs:IPAddrArrayPtr; len:integer);
  428.         var
  429.             tdrp:TDNRRecordPtr;
  430.             i:integer;
  431.             junk: OSStatus;
  432.     begin
  433.         tdrp := TDNRRecordPtr(token);
  434.         result := -900001;
  435.         if (tdrp <> nil) then begin
  436.             if not ValidDNR(token) then begin
  437.                 DebugStr('Invalid DNR Token;sc');
  438.             end else begin
  439.                 if have_OT then begin
  440.                     result := tdrp^.xhost.result;
  441.                     if result = noErr then begin
  442.                         if name <> nil then begin
  443.                             CopyC2P(@tdrp^.xhost.host.name, name^);
  444.                         end;
  445.                         for i := 1 to len do begin
  446.                             addrs^[i] := 0;
  447.                         end;
  448.                         for i := 1 to Min(kMaxHostAddrs, len) do begin
  449.                             addrs^[i] := tdrp^.xhost.host.addrs[i-1];
  450.                         end;
  451.                     end;
  452.                 end else begin
  453.                     result := tdrp^.dr.ioResult;
  454.                     if result = noErr then begin
  455.                         if name <> nil then begin
  456.                             name^ := tdrp^.canonical_name;
  457.                         end;
  458.                         for i := 1 to len do begin
  459.                             addrs^[i] := 0;
  460.                         end;
  461.                         for i := 1 to Min(len, 4) do begin
  462.                             addrs^[i] := tdrp^.dr.hi.addrs[i];
  463.                         end;
  464.                     end;
  465.                 end;
  466.                 if result <> inProgress then begin
  467.                     junk := Dequeue(QElemPtr(tdrp),@dnrs);
  468.                     Assert( junk = noErr );
  469.                     MDisposePtr(tdrp);
  470.                     token := nil;
  471.                 end;
  472.             end;
  473.         end;
  474.     end;
  475.     
  476.     function TransportAddrToName(addr: ipAddr; var token: Ptr): OSStatus;
  477.         var
  478.             err: OSStatus;
  479.             tdrp:TDNRRecordPtr;
  480.     begin
  481.         tdrp := nil;
  482.         err := OpenTransportSystem;
  483.         if err = noErr then begin
  484.             err := MNewPtr(tdrp, SizeOf(TDNRRecord));
  485.         end;
  486.         if err = noErr then begin
  487.             tdrp^.kind := TK_AddrToName;
  488.             tdrp^.dead := false;
  489.             if have_OT then begin
  490.                 tdrp^.xhost.result := inProgress;
  491.                 err := WaitForInternetServices;
  492.                 if err = noErr then begin
  493.                     err := OTInetAddressToName(is_ref, addr, tdrp^.xhost.host.name);
  494.                 end;
  495.             end else begin
  496.                 DNRAddrToName(addr, @tdrp^.dr, nil);
  497.                 err := noErr;
  498.             end;
  499.         end;
  500.         if err = noErr then begin
  501.             Enqueue(QElemPtr(tdrp),@dnrs);
  502.         end else begin
  503.             MDisposePtr(tdrp);
  504.         end;
  505.         token := Ptr(tdrp);
  506.         TransportAddrToName := err;
  507.     end;
  508.     
  509.     procedure TransportGetAddrToNameResult(var token: Ptr; var result: OSStatus; var name:Str255);
  510.         var
  511.             tdrp:TDNRRecordPtr;
  512.             junk: OSStatus;
  513.     begin
  514.         tdrp := TDNRRecordPtr(token);
  515.         result := -900002;
  516.         if tdrp <> nil then begin
  517.             if not ValidDNR(token) then begin
  518.                 DebugStr('Invalid DNR Token;sc');
  519.             end else begin
  520.                 if have_OT then begin
  521.                     result := tdrp^.xhost.result;
  522.                     if result = noErr then begin
  523.                         CopyC2P(@tdrp^.xhost.host.name, name);
  524.                     end;
  525.                 end else begin
  526.                     result := tdrp^.dr.ioResult;
  527.                     if result = noErr then begin
  528.                         name := tdrp^.dr.name;
  529.                     end;
  530.                 end;
  531.                 if result <> inProgress then begin
  532.                     junk := Dequeue(QElemPtr(tdrp),@dnrs);
  533.                     Assert( junk = noErr );
  534.                     MDisposePtr(tdrp);
  535.                     token := nil;
  536.                 end;
  537.             end;
  538.         end;
  539.         if (result = noErr) & (name[length(name)] = '.') then begin
  540.             Delete(name, length(name), 1);
  541.         end;
  542.     end;
  543.     
  544.     procedure TransportAbortDNR(var token: Ptr);
  545.         var
  546.             tdrp:TDNRRecordPtr;
  547.     begin
  548.         if token <> nil then begin
  549.             if not ValidDNR(token) then begin
  550.                 DebugStr('Invalid DNR Token;sc');
  551.             end else begin
  552.                 tdrp := TDNRRecordPtr(token);
  553.                 tdrp^.dead := true;
  554.             end;
  555.         end;
  556.     end;
  557.  
  558.     procedure IdleDNR(this:TDNRRecordPtr);
  559.         var
  560.             result: OSStatus;
  561.             name:Str255;
  562.     begin
  563.         case this^.kind of
  564.             TK_NameToAddr: begin
  565.                 TransportGetNameToAddrResult(Ptr(this), result, nil, nil, 0);
  566.             end;
  567.             TK_AddrToName: begin
  568.                 TransportGetAddrToNameResult(Ptr(this), result, name);
  569.             end;
  570.         end;
  571.     end;
  572.     
  573.     procedure OTAbortAllDNRs;
  574.         var
  575.             this, next:TDNRRecordPtr;
  576.     begin
  577.         if have_OT then begin
  578.             this := TDNRRecordPtr(dnrs.qHead);
  579.             while this <> nil do begin
  580.                 next := this^.next;
  581.                 if this^.xhost.result = inProgress then begin
  582.                     this^.xhost.result := kOTCanceledErr;
  583.                 end;
  584.                 this := next;
  585.             end;
  586.         end;
  587.     end;
  588.     
  589.     procedure IdleDNRs;
  590.         var
  591.             this, next:TDNRRecordPtr;
  592.     begin
  593.         this := TDNRRecordPtr(dnrs.qHead);
  594.         while this <> nil do begin
  595.             next := this^.next;
  596.             if this^.dead then begin
  597.                 IdleDNR(this);
  598.             end;
  599.             this := next;
  600.         end;
  601.     end;
  602.     
  603.     procedure WaitForDNRCompletions;
  604.         var
  605.             this:TDNRRecordPtr;
  606.     begin
  607.         if not have_OT then begin
  608.             while dnrs.qHead <> nil do begin
  609.                 this := TDNRRecordPtr(dnrs.qHead);
  610.                 IdleDNR(this);
  611.             end;
  612.         end;
  613.     end;
  614.  
  615.     procedure DNRNotifier( up: Boolean );
  616.     begin
  617.         if not up then begin
  618.             if have_OT then begin
  619.                 OTAbortAllDNRs;
  620.             end;
  621.             WaitForDNRCompletions;
  622.         end;
  623.     end;
  624.     
  625. { Deferred Tasks }
  626.     
  627.     procedure MyDeferredTaskHandlerPascal(dtp: MyDeferredTaskPtr);
  628.         var
  629.             olda5:Ptr;
  630.     begin
  631.         olda5 := SetPreservedA5;
  632.         dtp^.fired := true;
  633.         CallPascal04(dtp^.real_arg, dtp^.completion);
  634.         RestoreA5(olda5);
  635.     end;
  636.  
  637. {$IFC GENERATINGPOWERPC}
  638.     procedure MyDeferredTaskHandler(dtp: MyDeferredTaskPtr);
  639.     begin
  640.         MyDeferredTaskHandlerPascal(dtp);
  641.     end;
  642. {$ELSEC}
  643.     procedure MyDeferredTaskHandler;
  644.         var
  645.             param:MyDeferredTaskPtr;
  646.     begin
  647.         param := MyDeferredTaskPtr(GetRegA1);
  648.         MyDeferredTaskHandlerPascal(param);
  649.     end;
  650. {$ENDC}
  651.  
  652.     function TransportCreateDeferredTask(proc: OTProcessProcPtr; arg: UNIV Ptr): TransportDeferredTaskCookie;
  653.         var
  654.             dtp:MyDeferredTaskPtr;
  655.             result:longint;
  656.     begin
  657.         result := 0;
  658.         if have_OT & use_OT_tasks then begin
  659.             if OpenTransportSystem = noErr then begin
  660.                 result := OTCreateDeferredTask(proc, arg);
  661.             end;
  662.         end else begin
  663.             dtp := MyDeferredTaskPtr(NewPtr(SizeOf(MyDeferredTask)));
  664.             if dtp <> nil then begin
  665.                 dtp^.dt.dtAddr := gMyDeferredTaskHandlerProc;
  666.                 dtp^.dt.dtParam := longint(dtp);
  667.                 dtp^.dt.dtReserved := 0;
  668.                 dtp^.dt.dtFlags := 0;
  669.                 dtp^.dt.qType := ord(dtQType);
  670.                 dtp^.completion := NewProc(proc, uppPascal04ProcInfo);
  671.                 dtp^.real_arg := longint(arg);
  672.                 dtp^.fired := true;
  673.                 result := TransportDeferredTaskCookie(dtp);
  674.             end;
  675.         end;
  676.         TransportCreateDeferredTask := result;
  677.     end;
  678.  
  679.     procedure ScheduleDeferredTask(cookie:TransportDeferredTaskCookie);
  680.         var
  681.             dummy:Boolean;
  682.             dtp:MyDeferredTaskPtr;
  683.     begin
  684.         if have_OT & use_OT_tasks then begin
  685.             if  TransportSystemIsAlive = noErr then begin
  686.                 dummy := OTScheduleDeferredTask(cookie);
  687.             end;
  688.         end else begin
  689.             dtp := MyDeferredTaskPtr(cookie);
  690.             if dtp^.fired then begin
  691.                 if DTInstall(DeferredTaskPtr(dtp)) = noErr then begin
  692.                     dtp^.fired := false;
  693.                 end;
  694.             end;
  695.         end;
  696.     end;
  697.  
  698.     procedure DestroyDeferredTaskCookie(cookie:TransportDeferredTaskCookie);
  699.         var
  700.             junk:OSStatus;
  701.             dtp:MyDeferredTaskPtr;
  702.     begin
  703.         if have_OT & use_OT_tasks then begin
  704.             if  TransportSystemIsAlive = noErr then begin
  705.                 junk := OTDestroyDeferredTask(cookie);
  706.                 Assert( junk = noErr );
  707.             end;
  708.         end else begin
  709.             dtp := MyDeferredTaskPtr(cookie);
  710.             while not dtp^.fired do begin
  711.                 { wait til it fires since we can't abort it }
  712.             end;
  713.             DisposeRoutineDescriptor(dtp^.completion);
  714.             DisposePtr(Ptr(cookie));
  715.         end;
  716.     end;
  717.  
  718.     procedure TransportEnterInterrupt;
  719.     begin
  720.         if have_OT then begin
  721.             OTEnterInterrupt;
  722.         end;
  723.     end;
  724.     
  725.     procedure TransportLeaveInterrupt;
  726.     begin
  727.         if have_OT then begin
  728.             OTLeaveInterrupt;
  729.         end;
  730.     end;
  731. {
  732.     function ReopenInternetServicesOT: OSStatus;
  733.         var
  734.             err: OSStatus;
  735.     begin
  736.         if (is_ref = nil) & (is_result = kReopenInternetServices) then begin
  737.             is_result := inProgress;
  738.             err := OTAsyncOpenInternetServices(OTConfigurationPtr(kDefaultInternetServicesPath), 0, @InternetServicesHandler,nil);
  739.             if err <> noErr then begin
  740.                 is_result := err;
  741.             end;
  742.         end;
  743.         if is_result = inProgress then begin
  744.             err := noErr;
  745.         end else begin
  746.             err := is_result;
  747.         end;
  748.         ReopenInternetServicesOT := err;
  749.     end;
  750. }
  751.     function OpenTransportSystemOT:OSStatus;
  752.         var
  753.             err: OSStatus;
  754.             ep:EndpointRef;
  755.     begin
  756.         err := InitOpenTransport;
  757.         if err = noErr then begin
  758.             is_result := -900023;
  759.             is_ref := nil;
  760.             ep := OTOpenEndpoint( OTCreateConfiguration( "udp" ), 0, nil, err );
  761.             if err = noErr then begin
  762.                 MCloseProvider(ep);
  763.             end;
  764.             if err <> noErr then begin
  765.                 is_result := err;
  766.                 CloseOpenTransport;
  767.             end;
  768.         end;
  769.         OpenTransportSystemOT := err;
  770.     end;
  771.  
  772.     procedure CloseTransportSystemOT;
  773.     begin
  774.         CloseOpenTransport;
  775.     end;
  776.     
  777.     function TransportGetConnectionStateOT(ep: EndpointRef):TCPStateType;
  778.         var
  779.             result: OTResult;
  780.             state:TCPStateType;
  781.     begin
  782.         result := OTGetEndpointState(ep);
  783.         state := T_Dead;
  784.         if result >= 0 then begin
  785.             case result of
  786.                 T_UNINIT, T_UNBND:
  787.                     state := T_Dead;
  788.                 T_IDLE:begin
  789.                     state := T_Bored;
  790.                 end;
  791.                 T_INCON, T_OUTCON:
  792.                     state := T_Opening;
  793.                 T_DATAXFER:
  794.                     state := T_Established;
  795.                 T_OUTREL:
  796.                     state := T_Closing;
  797.                 T_INREL:
  798.                     state := T_PleaseClose;
  799.                 otherwise begin
  800.                     state := T_Unknown;
  801.                 end;
  802.             end;
  803.         end;
  804.         TransportGetConnectionStateOT := state;
  805.     end;
  806.  
  807. { MacTCP routines }
  808.  
  809.     function OpenTransportSystemMT:OSStatus;
  810.         var
  811.             err:OSStatus;
  812.     begin
  813.         err := OpenDriver('.IPP', mactcp_driver_refnum);
  814.         if err = noErr then begin
  815.             err := OpenResolver;
  816.         end;
  817.         OpenTransportSystemMT :=     err;
  818.     end;
  819.     
  820.     procedure CloseTransportSystemMT;
  821.     begin
  822.         CloseResolver;
  823.     end;
  824.  
  825. { Generic routines }
  826.  
  827.     function OpenTransportSystem:OSStatus;
  828.     begin
  829.         AssertDidStartup( startup_check );
  830.         if not calling_notifiers then begin
  831.             if (tcp_open_status = noErr) & (TransportSystemIsAlive <> noErr) then begin
  832.                 CloseTransportSystem;
  833.             end;
  834.             if (tcp_open_status <> noErr) & (TickCount >= last_reopen_time + max_reopen_frequency) then begin
  835.                 if have_OT then begin
  836.                     tcp_open_status := OpenTransportSystemOT;
  837.                 end else begin
  838.                     tcp_open_status := OpenTransportSystemMT;
  839.                 end;
  840.                 if tcp_open_status = noErr then begin
  841.                     transport_system_is_alive := true;
  842.                     CallTransitionNotifiers( true );
  843.                 end;
  844.                 last_reopen_time := TickCount;
  845.             end;
  846.         end;
  847.         OpenTransportSystem := tcp_open_status;
  848.     end;
  849.  
  850.     procedure CloseTransportSystem;
  851.     begin
  852.         if (tcp_open_status = noErr) then begin
  853.             transport_system_is_alive := false;
  854.             CallTransitionNotifiers( false );
  855.             if have_OT then begin
  856.                 CloseTransportSystemOT;
  857.             end else begin
  858.                 CloseTransportSystemMT;
  859.             end;
  860.             transport_system_is_alive := false;
  861.             tcp_open_status := userCanceledErr;
  862.         end;
  863.     end;
  864.  
  865.     function TransportGetMyIPAddr(var ip:ipAddr): OSStatus;
  866.         var
  867.             err: OSStatus;
  868.             cb: IPControlBlock;
  869.             info:InetInterfaceInfo;
  870.     begin
  871.         err := OpenTransportSystem;
  872.         if err = noErr then begin
  873.             if have_OT then begin
  874.                 err := OTInetGetInterfaceInfo(info, 0);
  875.                 ip := info.fAddress
  876.             end else begin
  877.                 MZero(@cb, SizeOf(cb));
  878.                 cb.ioCRefNum := mactcp_driver_refnum;
  879.                 cb.csCode := TCPcsGetMyIP;
  880.                 err := PBControlSync(@cb);
  881.                 ip := cb.getmyip.ourAddress;
  882.             end;
  883.         end;
  884.         TransportGetMyIPAddr := err;
  885.     end;
  886.     
  887. { Open }
  888.  
  889.     function CreateOTEndpoint(var ep:EndpointRef; config: OTConfigurationPtr; proc:OTNotifyProcPtr; context:univ Ptr):OSErr;
  890.         var
  891.             err: OSStatus;
  892.     begin
  893.         ep:=OTOpenEndpoint(config,0,nil,err);
  894.         if err = noErr then begin
  895.             if proc <> nil then begin
  896.                 err:=OTInstallNotifier(ep, proc, context);
  897.             end;
  898.             if err <> noErr then begin
  899.                 MCloseProvider(ep);
  900.             end;
  901.         end;
  902.         CreateOTEndpoint := err;
  903.     end;
  904.     
  905.     procedure OTInitNetbuf(var nb:TNetbuf; buf:Ptr; len:Size);
  906.     begin
  907.         nb.buf := buf;
  908.         nb.len := len;
  909.         nb.maxlen := len;
  910.     end;
  911.     
  912.     function SetReuseAddr(ep:EndpointRef):OSErr;
  913.         var
  914.             optreq:TOptMgmt;
  915.             optBuffer:record
  916.                 header:TOptionHeader;
  917.                 value:longint;
  918.             end;
  919.     begin
  920.         optreq.flags := T_NEGOTIATE;
  921.         OTInitNetbuf(optreq.opt, @optBuffer, kOTFourByteOptionSize);
  922.         optBuffer.header.len := kOTFourByteOptionSize;
  923.         optBuffer.header.level := INET_IP;
  924.         optBuffer.header.optName := IP_REUSEADDR;
  925.         optBuffer.header.status := 0;
  926.         optBuffer.value := $01000000;
  927.         SetReuseAddr := OTOptionManagement(ep, @optreq, @optreq);
  928.     end;
  929.  
  930.     function BindOTListener(ep:EndpointRef; var localport:ipPort; listeners:integer):OSErr;
  931.         var
  932.             err:OSStatus;
  933.             reqsin, retsin:InetAddress;
  934.             req, ret:TBind;
  935.     begin
  936.         MZero(@req, sizeof(req));
  937.         err := noErr;
  938.         if localport <> 0 then begin
  939.             err := SetReuseAddr(ep);
  940.             OTInitInetAddress(reqsin, localport, 0);
  941.             OTInitNetbuf(req.addr, @reqsin, sizeof(InetAddress));
  942.         end else begin
  943.             OTInitNetbuf(req.addr, nil, 0);
  944.         end;
  945.         req.qlen := listeners;
  946.         
  947.         MZero(@ret, sizeof(ret));
  948.         OTInitNetbuf(ret.addr, @retsin, sizeof(InetAddress));
  949.         
  950.         if err = noErr then begin
  951.             err := OTBind(ep, @req, @ret);
  952.             if (err = noErr) & (localport <> 0) & (localport <> retsin.fPort) then begin
  953.                 err := couldNotGetRequestedPortErr;
  954.             end;
  955.             localport := retsin.fPort;
  956.         end;
  957.         
  958.         if err = noErr then begin
  959.             err:=OTSetAsynchronous(ep);
  960.         end;
  961.         BindOTListener := err;
  962.     end;
  963.     
  964.     procedure EventHandlerOT (btp:TransportRecordPtr; event: OTEventCode; result: OTResult; cookie: univ Ptr);
  965.         var
  966.             junk:OSStatus;
  967.             getprotaddr_resultp: LongIntPtr;
  968.     begin
  969. {$unused(cookie)}
  970.         case event of
  971.             T_OPENCOMPLETE: begin
  972.             end;
  973.             T_ACCEPTCOMPLETE:  begin
  974.                 btp^.accept_result := result;
  975.                 btp^.accept_received := true;
  976.             end;
  977.             T_PASSCON: begin
  978.                 btp^.passcon_result := result;
  979.                 btp^.passcon_received := true;
  980.             end;
  981.             T_CONNECT:  begin
  982.                 btp^.connect_result := result;
  983.                 junk := OTRcvConnect(btp^.ep, @btp^.rcvCall);
  984.                 { Assert( junk = noErr ); }
  985.                 if junk <> noErr then begin
  986.                     btp^.connect_result := -12345;
  987.                 end;
  988.                 btp^.connect_received := true;
  989.             end;
  990.             T_DISCONNECT:  begin
  991.                 btp^.connect_result := result;
  992.                 btp^.disconnect_received := true;
  993.                 junk := OTRcvDisconnect( btp^.ep, nil ); 
  994.                 { Assert( junk = noErr ); }
  995.             end;
  996.             T_GETPROTADDRCOMPLETE: begin
  997.                 Assert( result <> inProgress );
  998.                 getprotaddr_resultp := LongIntPtr( ord4(cookie) - 4 );
  999.                 Assert( getprotaddr_resultp^ = inProgress );
  1000.                 getprotaddr_resultp^ := result
  1001.             end;
  1002.             T_ORDREL:  begin
  1003.                 junk := OTRcvOrderlyDisconnect( btp^.ep );
  1004.                 Assert( junk = noErr );
  1005.             end;
  1006.             T_DATA, T_GODATA: begin
  1007.                 if (btp^.wake_process.highLongOfPSN <> 0) or (btp^.wake_process.lowLongOfPSN <> kNoProcess) then begin
  1008.                     junk := WakeUpProcess(btp^.wake_process);
  1009.                 end;
  1010.             end;
  1011.             T_DISCONNECTCOMPLETE: begin
  1012.             end;
  1013.             T_MEMORYRELEASED: begin
  1014.                 if btp^.MemoryReleasedHandler <> nil then begin
  1015.                     btp^.MemoryReleasedHandler(TransportRef(btp), result, cookie);
  1016.                 end;
  1017.             end;
  1018.             otherwise
  1019.                 ;
  1020.         end;
  1021.     end;
  1022.  
  1023.     function ValidTransport(tref:TransportRef): Boolean;
  1024.         var
  1025.             this:TransportRecordPtr;
  1026.     begin
  1027.         ValidTransport := false;
  1028.         this := TransportRecordPtr(transports.qHead);
  1029.         while this <> nil do begin
  1030.             if TransportRef(this) = tref then begin
  1031.                 ValidTransport := true;
  1032.                 leave;
  1033.             end;
  1034.             this := this^.next;
  1035.         end;
  1036.     end;
  1037.     
  1038.     procedure TransportDestroy(var tref:TransportRef);
  1039.         var
  1040.             btp:TransportRecordPtr;
  1041.             junk:OSStatus;
  1042.     begin
  1043.         btp := TransportRecordPtr(tref);
  1044.         if btp <> nil then begin
  1045.             Assert(ValidTransport(tref));
  1046.             if TransportSystemIsAlive = noErr then begin
  1047.                 if have_OT then begin
  1048.                     if btp^.ep <> nil then begin
  1049.                         MCloseProvider(btp^.ep);
  1050.                     end;
  1051.                 end else begin
  1052.                     if btp^.stream <> nil then begin
  1053.                         junk := MTTCPRelease(btp^.stream);
  1054.                         Assert( junk = noErr );
  1055.                     end;
  1056.                     MDisposePtr(btp^.stream_buffer);
  1057.                     TransportAbortDNR(btp^.dnr_token);
  1058.                 end;
  1059.             end;
  1060.             MDisposeHandle(btp^.input_handle);
  1061.             MDisposeHandle(btp^.output_handle);
  1062.             MDisposeHandle(btp^.sending_handle);
  1063.             junk:=Dequeue(QElemPtr(btp),@transports);
  1064.             Assert( junk = noErr );
  1065.             MDisposePtr(btp);
  1066.             tref := nil;
  1067.         end;
  1068.     end;
  1069.     
  1070.     function TransportCreate(var btp:TransportRecordPtr; buffer_size:longint):OSStatus;
  1071.         var
  1072.             err:OSStatus;
  1073.             hack_mrp: MemoryReleasedProc;
  1074.     begin
  1075.         hack_mrp := hack_MemoryReleasedProc;
  1076.         hack_MemoryReleasedProc := nil;
  1077.         buffer_size := Pin(10240, buffer_size, 64512);
  1078.         btp := nil;
  1079.         err := OpenTransportSystem;
  1080.         if err = noErr then begin
  1081.             err := MNewPtr(btp, SizeOf(TransportRecord));
  1082.             if err = noErr then begin
  1083.                 Enqueue(QElemPtr(btp),@transports);
  1084.                 btp^.input_handle := nil;
  1085.                 btp^.output_handle := nil;
  1086.                 btp^.sending_handle := nil;
  1087.                 btp^.max_input_handle_size := 10240;
  1088.                 if have_OT then begin
  1089.                     btp^.MemoryReleasedHandler := hack_mrp;
  1090.                     btp^.wake_process.highLongOfPSN := 0;
  1091.                     btp^.wake_process.lowLongOfPSN := kNoProcess;
  1092.                     btp^.waiting_for_connect := false;
  1093.                     btp^.connect_received := false;
  1094.                     btp^.accept_received := false;
  1095.                     btp^.passcon_received := false;
  1096.                     btp^.disconnect_received := false;
  1097.                     err := CreateOTEndpoint(btp^.ep, OTCreateConfiguration( "tcp" ), @EventHandlerOT, btp);
  1098.                     if (err = noErr) & (btp^.MemoryReleasedHandler <> nil) then begin
  1099.                         err := OTAckSends(btp^.ep);
  1100.                     end;
  1101.                 end else begin
  1102.                     btp^.dnr_token := nil;
  1103.                     btp^.stream := nil;
  1104.                     btp^.send_cb.ioResult := noErr;
  1105.                     err := MNewPtr(btp^.stream_buffer, buffer_size);
  1106.                     if err = noErr then begin
  1107.                         err := MTTCPCreate(btp^.stream, btp^.stream_buffer, buffer_size);
  1108.                     end;
  1109.                 end;
  1110.                 btp^.started_opening := false;
  1111.                 btp^.handle_receives := false;
  1112.                 btp^.handle_sends := false;
  1113.                 btp^.do_send_close := false;
  1114.                 btp^.send_error := noErr;
  1115.                 btp^.open_result := inProgress;
  1116.                 btp^.tstate := T_Bored;
  1117.                 btp^.receive_error := noErr;
  1118.                 if err <> noErr then begin
  1119.                     TransportDestroy(TransportRef(btp));
  1120.                 end;
  1121.             end;
  1122.         end;
  1123.         TransportCreate := err;
  1124.     end;
  1125.     
  1126.     function TransportHandleReceives(tref:TransportRef): OSStatus;
  1127.         var
  1128.             err, junk: OSStatus;
  1129.             btp:TransportRecordPtr;
  1130.     begin
  1131.         btp := TransportRecordPtr(tref);
  1132.         Assert(btp <> nil);
  1133.         Assert(ValidTransport(tref));
  1134.         err := noErr;
  1135.         if not btp^.handle_receives then begin
  1136.             junk := GetCurrentProcess(btp^.wake_process);
  1137.             Assert( junk = noErr );
  1138.             err := MNewHandle(btp^.input_handle, 0);
  1139.             btp^.handle_receives := err = noErr;            
  1140.         end;
  1141.         TransportHandleReceives := err;
  1142.     end;
  1143.     
  1144.     function TransportHandleSends(tref:TransportRef): OSStatus;
  1145.         var
  1146.             err, err2: OSStatus;
  1147.             btp:TransportRecordPtr;
  1148.     begin
  1149.         btp := TransportRecordPtr(tref);
  1150.         Assert(btp <> nil);
  1151.         Assert(ValidTransport(tref));
  1152.         err := noErr;
  1153.         if not btp^.handle_sends then begin
  1154.             err := MNewHandle(btp^.output_handle, 0);
  1155.             err2 := MNewHandle(btp^.sending_handle, 0);
  1156.             if err = noErr then begin
  1157.                 err := err2;
  1158.             end;
  1159.             btp^.handle_sends := err = noErr;
  1160.         end;
  1161.         TransportHandleSends := err;
  1162.     end;
  1163.  
  1164.     function TransportHandleTransfers(tref:TransportRef): OSStatus;
  1165.         var
  1166.             err: OSStatus;
  1167.     begin
  1168.         err := TransportHandleReceives(tref);
  1169.         if err = noErr then begin
  1170.             err :=TransportHandleSends(tref);
  1171.         end;
  1172.         TransportHandleTransfers := err;
  1173.     end;
  1174.     
  1175.     function TransportOpenActiveConnection(var tref:TransportRef; dest:Str255; localport:ipPort; buffer_size:longint): OSStatus;
  1176.         var
  1177.             btp:TransportRecordPtr;
  1178.             err: OSStatus;
  1179.             portstr:Str255;
  1180.             n:longint;
  1181.     begin
  1182.         err := TransportCreate(btp, buffer_size);
  1183.         if err = noErr then begin
  1184.             if have_OT then begin
  1185.                 err := BindOTListener(btp^.ep, localport, 0);
  1186.                 if err = noErr then begin
  1187.                     err:=OTSetAsynchronous(btp^.ep);
  1188.                 end;
  1189.                 if err = noErr then begin
  1190.                     MZero(@btp^.rcvCall, sizeof(btp^.rcvCall));
  1191.                     OTInitNetbuf(btp^.rcvCall.addr, @btp^.rcvsin, sizeof(InetAddress));
  1192.         
  1193.                     MZero(@btp^.sndCall, sizeof(btp^.sndCall));
  1194.                     P2C(@dest);
  1195.                     OTInitNetbuf(btp^.sndCall.addr, @btp^.sndsin, OTInitDNSAddress(btp^.sndsin, @dest));
  1196.                     
  1197.                     err := OTConnect(btp^.ep, @btp^.sndCall, @btp^.rcvCall);
  1198.                     if err = kOTNoDataErr then begin
  1199.                         err := noErr;
  1200.                     end;
  1201.                 end;
  1202.             end else begin
  1203.                 SplitBy (dest, ':', dest, portstr);
  1204.                 StringToNum(portstr, n);
  1205.                 btp^.remote_port := n;
  1206.                 btp^.local_port := localport;
  1207.                 err := TransportNameToAddr(dest, btp^.dnr_token);
  1208.             end;
  1209.             btp^.started_opening := true;
  1210.             if err <> noErr then begin
  1211.                 TransportDestroy(TransportRef(btp));
  1212.             end;
  1213.         end;
  1214.         tref := TransportRef(btp);
  1215.         TransportOpenActiveConnection := err;
  1216.     end;
  1217.  
  1218.     function TransportOpenPassiveConnection(var tref:TransportRef; var localport:ipPort; buffer_size:longint): OSStatus;
  1219.         var
  1220.             btp:TransportRecordPtr;
  1221.             err:OSStatus;
  1222.     begin
  1223.         err := TransportCreate(btp, buffer_size);
  1224.         if err = noErr then begin
  1225.             if have_OT then begin
  1226.                 btp^.waiting_for_connect := true;
  1227.                 err := BindOTListener(btp^.ep, localport, 1);
  1228.             end else begin
  1229.                 err := MTTCPPassiveOpen(btp^.open_cb, btp^.stream, localport);
  1230.             end;
  1231.             btp^.started_opening := true;
  1232.             if err <> noErr then begin
  1233.                 TransportDestroy(TransportRef(btp));
  1234.             end;
  1235.         end;
  1236.         tref := TransportRef(btp);
  1237.         TransportOpenPassiveConnection := err;
  1238.     end;
  1239.     
  1240.     procedure TransportGetOpenResult(tref:TransportRef; var result: OSStatus);
  1241.         var
  1242.             btp:TransportRecordPtr;
  1243.     begin
  1244.         btp := TransportRecordPtr(tref);
  1245.         Assert(btp <> nil);
  1246.         Assert(ValidTransport(tref));
  1247.         result := btp^.open_result
  1248.     end;
  1249.     
  1250.     procedure ProcessOpen(btp:TransportRecordPtr);
  1251.         var
  1252.             addr:ipAddr;
  1253.             result: OSStatus;
  1254.     begin
  1255.         Assert(btp <> nil);
  1256.         if btp^.started_opening & (btp^.open_result = inProgress) then begin
  1257.             if have_OT then begin
  1258.                 if btp^.waiting_for_connect then begin
  1259.                     MZero(@btp^.rcvCall, sizeof(btp^.rcvCall));
  1260.                     OTInitNetbuf(btp^.rcvCall.addr, @btp^.rcvsin, sizeof(InetAddress));
  1261.                     result := OTListen(btp^.ep, @btp^.rcvCall);
  1262.                     if result = kOTNoDataErr then begin
  1263.                         result := inProgress;
  1264.                     end else begin
  1265.                         btp^.waiting_for_connect := false;
  1266.                         if result = noErr then begin
  1267.                             result := OTAccept(btp^.ep, btp^.ep, @btp^.rcvCall);
  1268.                         end;
  1269.                     end;
  1270.                 end else if btp^.disconnect_received then begin
  1271.                     result := connectionDoesntExistErr;
  1272.                 end else if btp^.connect_received then begin
  1273.                     result := btp^.connect_result;
  1274.                 end else if btp^.accept_received then begin
  1275.                     result := btp^.accept_result;
  1276.                 end else if btp^.passcon_received then begin
  1277.                     result := btp^.passcon_result;
  1278.                 end else begin
  1279.                     result := inProgress;
  1280.                 end;
  1281.             end else begin
  1282.                 result := noErr;
  1283.                 if btp^.dnr_token <> nil then begin
  1284.                     TransportGetNameToAddrResult(btp^.dnr_token, result, nil, @addr, 1);
  1285.                     if result = noErr then begin
  1286.                         result := MTTCPActiveOpen(btp^.open_cb, btp^.stream, btp^.local_port, addr, btp^.remote_port);
  1287.                     end;
  1288.                 end;
  1289.                 if result = noErr then begin
  1290.                     result := btp^.open_cb.ioResult;
  1291.                 end;
  1292.             end;
  1293.             btp^.open_result := result;
  1294.         end;
  1295.     end;
  1296.  
  1297.     procedure IdleReceive(btp:TransportRecordPtr);
  1298.         var
  1299.             err: OSStatus;
  1300.             result: OTResult;
  1301.             flags:OTFlags;
  1302.             cb:TCPControlBlock;
  1303.             len, count: longint;
  1304.     begin
  1305.         if btp^.handle_receives then begin
  1306.             len := MGetHandleSize(btp^.input_handle);
  1307.             if have_OT then begin
  1308.                 if len < btp^.max_input_handle_size then begin
  1309.                     result := OTRcv(btp^.ep, idle_space, Min( btp^.max_input_handle_size-len, GetPtrSize(idle_space) ), flags);
  1310.                     if result >= 0 then begin
  1311.                         err := PtrAndHand(idle_space, btp^.input_handle, result);
  1312.                     end else begin
  1313.                         case result of
  1314.                             kOTNoDataErr: begin
  1315.                                 err := noErr;
  1316.                             end;
  1317.                             kOTOutStateErr: begin
  1318.                                 err := connectionClosingErr;
  1319.                             end;
  1320.                             otherwise begin
  1321.                                 err := result;
  1322.                             end;
  1323.                         end;
  1324.                     end;
  1325.                     if err <> noErr then begin
  1326.                         btp^.receive_error := err;
  1327.                     end;
  1328.                 end;
  1329.             end else begin
  1330.                 MTZeroTCPCB(cb, btp^.stream, TCPcsStatus);
  1331.                 err := PBControlSync(@cb);
  1332.                 if err = noErr then begin
  1333.                     count := Min(cb.status.amtUnreadData, 10240 - len);
  1334.                     if count > 0 then begin
  1335.                         err := MSetHandleSize(btp^.input_handle, len + count);
  1336.                         if err = noErr then begin
  1337.                             HLock(btp^.input_handle);
  1338.                             MTZeroTCPCB(cb, btp^.stream, TCPcsRcv);
  1339.                             cb.receive.rcvBuff := btp^.input_handle^;
  1340.                             cb.receive.rcvBuffLength := count;
  1341.                             err := PBControlSync(@cb);
  1342.                             count := cb.receive.rcvBuffLength;
  1343.                             HUnlock(btp^.input_handle);
  1344.                         end;
  1345.                         if err <> noErr then begin
  1346.                             count := 0;
  1347.                             btp^.receive_error := err;
  1348.                         end;
  1349.                         SetHandleSize(btp^.input_handle, len + count);
  1350.                     end else begin
  1351.                         if MTMapState( cb.status.connectionState ) in [T_Dead, T_Bored, T_PleaseClose] then begin
  1352.                             err := connectionClosingErr;
  1353.                         end;
  1354.                     end;
  1355.                 end;
  1356.             end;
  1357.         end;
  1358.     end;
  1359.     
  1360.     function TransportCharsAvailable(tref:TransportRef): longint;
  1361.         var
  1362.             btp:TransportRecordPtr;
  1363.     begin
  1364.         btp := TransportRecordPtr(tref);
  1365.         Assert(btp <> nil);
  1366.         Assert(ValidTransport(tref));
  1367.         Assert(btp^.handle_receives);
  1368.         TransportCharsAvailable := MGetHandleSize(btp^.input_handle);
  1369.     end;
  1370.     
  1371.     function TransferPeekCharsAvailable(tref:TransportRef; const look: Str255): longint;
  1372.         var
  1373.             btp:TransportRecordPtr;
  1374.     begin
  1375.         btp := TransportRecordPtr(tref);
  1376.         Assert(btp <> nil);
  1377.         Assert(ValidTransport(tref));
  1378.         Assert(btp^.handle_receives);
  1379.         TransferPeekCharsAvailable := MMungerFindString( btp^.input_handle, 0, look );
  1380.     end;
  1381.     
  1382.     function TransportReceive(tref:TransportRef; buf: Ptr; len:longint; var count:longint): OSStatus;
  1383.         var
  1384.             btp:TransportRecordPtr;
  1385.             err: OSStatus;
  1386.             size: longint;
  1387.     begin
  1388.         btp := TransportRecordPtr(tref);
  1389.         Assert(btp <> nil);
  1390.         Assert(ValidTransport(tref));
  1391.         Assert(btp^.handle_receives);
  1392.         size := MGetHandleSize(btp^.input_handle);
  1393.         if size > 0 then begin
  1394.             err := noErr;
  1395.             count := Min(len, size);
  1396.             if count > 0 then begin
  1397.                 BlockMoveData(btp^.input_handle^, buf, count);
  1398.                 MMungerDelete(btp^.input_handle, 0, count);
  1399.             end;
  1400.         end else if btp^.receive_error = noErr then begin
  1401.             err := noErr;
  1402.             count := 0;
  1403.         end else begin
  1404.             err := btp^.receive_error;
  1405.             btp^.receive_error := noErr;
  1406.             count := 0;
  1407.         end;
  1408.         TransportReceive := err;
  1409.     end;
  1410.     
  1411.     function TransportSend(tref:TransportRef; buf: Ptr; len:longint): OSStatus;
  1412.         var
  1413.             btp:TransportRecordPtr;
  1414.             err: OSStatus;
  1415.     begin
  1416.         btp := TransportRecordPtr(tref);
  1417.         Assert(btp <> nil);
  1418.         Assert(ValidTransport(tref));
  1419.         if not btp^.handle_sends then begin
  1420.             err := -900005; { I'd like to know why this actually occurs }
  1421.         end else begin
  1422.             err := PtrAndHand(buf, btp^.output_handle, len);
  1423.             if err = noErr then begin
  1424.                 err := btp^.send_error;
  1425.                 btp^.send_error:= noErr;
  1426.             end;
  1427.         end;
  1428.         TransportSend := err;
  1429.     end;
  1430.     
  1431.     function TransportSendQueued(tref:TransportRef): longint;
  1432.         var
  1433.             btp:TransportRecordPtr;
  1434.             result: longint;
  1435.     begin
  1436.         btp := TransportRecordPtr(tref);
  1437.         Assert(btp <> nil);
  1438.         Assert(ValidTransport(tref));
  1439.         if not btp^.handle_sends then begin
  1440.             result := 0;
  1441.         end else begin
  1442.             result := MGetHandleSize( btp^.output_handle );
  1443.         end;
  1444.         TransportSendQueued := result;
  1445.     end;
  1446.     
  1447.     procedure IdleSend(btp: TransportRecordPtr);
  1448.         procedure SwapHandles(var h1, h2:Handle);
  1449.             var
  1450.                 tmph:Handle;
  1451.         begin
  1452.             tmph := h1;
  1453.             h1 := h2;
  1454.             h2 := tmph;
  1455.         end;
  1456.         var
  1457.             err: OSStatus;
  1458.             result: OTResult;
  1459.             len:longint;
  1460.     begin
  1461.         if btp^.handle_sends then begin
  1462.             len := MGetHandleSize(btp^.output_handle);
  1463.             if btp^.do_send_close & (len = 0) then begin
  1464.                 btp^.handle_sends := false;
  1465.                 TransportSendClose(TransportRef(btp));
  1466.             end else begin
  1467.                 if have_OT then begin
  1468.                     if len > 0 then begin
  1469.                         HLock(btp^.output_handle);
  1470.                         result := OTSnd(btp^.ep, btp^.output_handle^, len, 0);
  1471.                         HUnlock(btp^.output_handle);
  1472.                         if result >= 0 then begin
  1473.                             MMungerDelete(btp^.output_handle, 0, result);
  1474.                         end else if result <> kOTFlowErr then begin
  1475.                             btp^.send_error := result;
  1476.                             SetHandleSize(btp^.output_handle, 0);
  1477.                         end;
  1478.                     end;
  1479.                 end else begin
  1480.                     if btp^.send_cb.ioResult <> inProgress then begin
  1481.                         HUnlock(btp^.sending_handle);
  1482.                         SetHandleSize(btp^.sending_handle, 0);
  1483.                         if btp^.send_cb.ioResult <> noErr then begin
  1484.                             btp^.send_error := btp^.send_cb.ioResult;
  1485.                             btp^.send_cb.ioResult := noErr;
  1486.                         end;
  1487.                         if len > 0 then begin
  1488.                             SwapHandles(btp^.output_handle, btp^.sending_handle);
  1489.                             HLock(btp^.sending_handle);
  1490.                             btp^.send_wds.buffer := btp^.sending_handle^;
  1491.                             btp^.send_wds.size := len;
  1492.                             btp^.send_wds.term := 0;
  1493.                             MTZeroTCPCB(btp^.send_cb, btp^.stream, TCPcsSend);
  1494.                             btp^.send_cb.send.wds := @btp^.send_wds;
  1495.                             btp^.send_cb.send.pushFlag := 1;
  1496.                             err := PBControlAsync(@btp^.send_cb);
  1497.                         end;
  1498.                     end;
  1499.                 end;
  1500.             end;
  1501.         end;
  1502.     end;
  1503.  
  1504.     procedure TransportSendClose(tref:TransportRef);
  1505.         var
  1506.             btp:TransportRecordPtr;
  1507.             err: OSStatus;
  1508.     begin
  1509.         btp := TransportRecordPtr(tref);
  1510.         Assert(btp <> nil);
  1511.         Assert(ValidTransport(tref));
  1512.         err := TransportSystemIsAlive;
  1513.         if err = noErr then begin
  1514.             if btp^.handle_sends then begin
  1515.                 btp^.do_send_close := true;
  1516.                 IdleSend(btp);
  1517.             end else begin
  1518.                 if have_OT then begin
  1519.                     err := OTSndOrderlyDisconnect(btp^.ep);
  1520.                 end else begin
  1521.                     err := MTTCPClose(btp^.close_cb, btp^.stream);
  1522.                 end;
  1523.             end;
  1524.         end;
  1525.     end;
  1526.     
  1527.     function TransportGetConnectionStateInteruptSafe (tref:TransportRef): TCPStateType; { * }
  1528.         var
  1529.             btp:TransportRecordPtr;
  1530.             state:TCPStateType;
  1531.     begin
  1532.         btp := TransportRecordPtr(tref);
  1533.         if (btp = nil) then begin {  | (TransportSystemIsAlive <> noErr) }
  1534.             state := T_Dead;
  1535.         end else if have_OT then begin
  1536.             state := TransportGetConnectionStateOT(btp^.ep);
  1537.         end else begin
  1538.             state := btp^.tstate;
  1539.         end;
  1540.         TransportGetConnectionStateInteruptSafe := state;
  1541.     end;
  1542.  
  1543.     procedure IdleMacTCPConnectionState(btp:TransportRecordPtr);
  1544.     begin
  1545.         Assert(not have_OT);
  1546.         if btp^.dnr_token <> nil then begin
  1547.             btp^.tstate := T_Opening;
  1548.         end else if btp^.stream = nil then begin
  1549.             btp^.tstate := T_Dead;
  1550.         end else begin
  1551.             btp^.tstate := MTTCPState(btp^.stream);
  1552.         end;
  1553.     end;
  1554.     
  1555.     function TransportGetConnectionState (tref:TransportRef): TCPStateType;
  1556.         var
  1557.             btp:TransportRecordPtr;
  1558.             state:TCPStateType;
  1559.     begin
  1560.         btp := TransportRecordPtr(tref);
  1561.         if (btp = nil) | (TransportSystemIsAlive <> noErr) then begin
  1562.             state := T_Dead;
  1563.         end else if have_OT then begin
  1564.             state := TransportGetConnectionStateOT(btp^.ep);
  1565.         end else begin
  1566.             btp^.tstate := MTTCPState(btp^.stream);
  1567.             state := btp^.tstate;
  1568.         end;
  1569.         TransportGetConnectionState := state;
  1570.     end;
  1571.     
  1572.     procedure TransportLowGetStreamPtr(tref:TransportRef; var stream: StreamPtr);
  1573.         var
  1574.             btp:TransportRecordPtr;
  1575.     begin
  1576.         btp := TransportRecordPtr(tref);
  1577.         Assert(btp <> nil);
  1578.         Assert(ValidTransport(tref));
  1579.         Assert(not have_OT);
  1580.         stream := btp^.stream;
  1581.     end;
  1582.     
  1583.     procedure TransportLowGetEndpointRef(tref:TransportRef; var ep: EndpointRef);
  1584.         var
  1585.             btp:TransportRecordPtr;
  1586.     begin
  1587.         btp := TransportRecordPtr(tref);
  1588.         Assert(btp <> nil);
  1589.         Assert(have_OT);
  1590.         Assert(ValidTransport(tref));
  1591.         ep := btp^.ep;
  1592.     end;
  1593.  
  1594.     function TransportLowSetOTAckSends(tref:TransportRef; handler: MemoryReleasedProc): OSStatus;
  1595.         var
  1596.             err: OSStatus;
  1597.             btp:TransportRecordPtr;
  1598.     begin
  1599.         btp := TransportRecordPtr(tref);
  1600.         Assert(btp <> nil);
  1601.         Assert(ValidTransport(tref));
  1602.         Assert(have_OT);
  1603.         err := OpenTransportSystem;
  1604.         if err = noErr then begin
  1605.             if btp^.MemoryReleasedHandler = nil then begin
  1606.                 err := OTAckSends(btp^.ep);
  1607.             end;
  1608.             if err = noErr then begin
  1609.                 btp^.MemoryReleasedHandler := handler;
  1610.             end;
  1611.         end;
  1612.         TransportLowSetOTAckSends := err;
  1613.     end;
  1614.  
  1615.     function SafeOTGetPortsSync( btp: TransportRecordPtr; var localip: ipAddr; var localport: ipPort; var remoteip: ipAddr; var remoteport: ipPort): OSStatus;
  1616.         type
  1617.             HackBindRecord = record
  1618.                     localBind: TBind;
  1619.                     result: OSStatus; { must preceed peer address! }
  1620.                     remoteBind: TBind;
  1621.                     localAddr: InetAddress;
  1622.                     remoteAddr: InetAddress;
  1623.                 end;
  1624.             HackBindRecordPtr = ^HackBindRecord;
  1625.         
  1626.         var
  1627.             err: OSStatus;
  1628.             bind: HackBindRecordPtr;
  1629.             timeout: longint;
  1630.     begin
  1631.         err := MNewPtr( bind, SizeOf(HackBindRecord) );
  1632.         if err = noErr then begin
  1633.             bind^.result := inProgress;
  1634.             OTInitNetbuf(bind^.localBind.addr, @bind^.localAddr, SizeOf(bind^.localAddr));
  1635.             OTInitNetbuf(bind^.remoteBind.addr, @bind^.remoteAddr, SizeOf(bind^.remoteAddr));
  1636.             err := OTGetProtAddress(btp^.ep, @bind^.localBind, @bind^.remoteBind);
  1637.             if err = noErr then begin
  1638.                 timeout := TickCount + 10;
  1639.                 while (TickCount < timeout) & (bind^.result = inProgress) do begin
  1640.                     OTIdle;
  1641.                 end;
  1642.                 if bind^.result = inProgress then begin
  1643.                     err := commandTimeoutErr;
  1644. {$ifc do_debug}
  1645.                     DebugStr( 'NetPresenz:SafeOTGetPortsSync: Abandoning BindRecord;g' );
  1646. {$endc}
  1647.                     { abandon the ptr, sigh }
  1648.                 end else begin
  1649.                     err := bind^.result;
  1650.                     localip := bind^.localAddr.fHost;
  1651.                     localport := bind^.localAddr.fPort;
  1652.                     remoteip := bind^.remoteAddr.fHost;
  1653.                     remoteport := bind^.remoteAddr.fPort;
  1654.                     MDisposePtr( bind );
  1655.                 end;
  1656.             end;
  1657.         end;
  1658.         SafeOTGetPortsSync := err;
  1659.     end;
  1660.     
  1661.     function TransportGetPorts(tref:TransportRef; var localip: ipAddr; var localport: ipPort; var remoteip: ipAddr; var remoteport: ipPort): OSStatus;
  1662.         var
  1663.             err: OSStatus;
  1664.             btp: TransportRecordPtr;
  1665.             cb: TCPControlBlock;
  1666.     begin
  1667.         btp := TransportRecordPtr(tref);
  1668.         Assert(btp <> nil);
  1669.         Assert(ValidTransport(tref));
  1670.         err := TransportSystemIsAlive;
  1671.         if err = noErr then begin
  1672.             if have_OT then begin
  1673.                 err := SafeOTGetPortsSync( btp, localip, localport, remoteip, remoteport );
  1674.             end else begin
  1675.                 MTZeroTCPCB(cb, btp^.stream, TCPcsStatus);
  1676.                 err := PBControlSync(@cb);
  1677.                 if err = noErr then begin
  1678.                     localip := cb.status.localhost;
  1679.                     localport := cb.status.localport;
  1680.                     remoteip := cb.status.remotehost;
  1681.                     remoteport := cb.status.remoteport;
  1682.                 end;
  1683.             end;
  1684.         end;
  1685.         if err <> noErr then begin
  1686.             localip := 0;
  1687.             localport := 0;
  1688.             remoteip := 0;
  1689.             remoteport := 0;
  1690.         end;
  1691.         TransportGetPorts := err;
  1692.     end;
  1693.     
  1694.     const
  1695.         max_tcp_listeners = 20;
  1696.     
  1697.     type
  1698.         OTSequenceArray = array[0..1000] of OTSequence;
  1699.         OTSequenceArrayPtr = ^OTSequenceArray;
  1700.         OTSequenceArrayHandle = ^OTSequenceArrayPtr;
  1701.     
  1702.     type
  1703.         TransportListenRecord = record
  1704.             localport: ipPort;
  1705.             case boolean of
  1706.             false:(
  1707.                 mt_buffer_size:longint;
  1708.                 mt_listeners_count:integer;
  1709.                 mt_listeners:array[1..max_tcp_listeners] of TransportRef;
  1710.             )
  1711.             true:(
  1712.                 ep: EndpointRef;
  1713.                 sequences: OTSequenceArrayHandle;
  1714.             )
  1715.         end;
  1716.         TransportListenRecordPtr = ^TransportListenRecord;
  1717.  
  1718.     function TransportListen(var token:Ptr; localport:ipPort; listeners:integer; buffer_size:longint):OSStatus;
  1719.         var
  1720.             lp:TransportListenRecordPtr;
  1721.             err, junk:OSStatus;
  1722.             i:integer;
  1723.     begin
  1724.         lp := nil;
  1725.         err := OpenTransportSystem;
  1726.         if err = noErr then begin
  1727.             err := MNewPtr(lp, SizeOf(TransportListenRecord));
  1728.             if err = noErr then begin
  1729.                 lp^.localport := localport;
  1730.                 if have_OT then begin
  1731.                     err := MNewHandle(lp^.sequences, 0);
  1732.                     if err = noErr then begin
  1733.                         if false & (ot_version >= kOTTILISTENVersion) then begin
  1734.                             err := CreateOTEndpoint(lp^.ep, OTCreateConfiguration( "tilisten, tcp" ), nil, lp);
  1735.                         end else begin
  1736.                             err := -1;
  1737.                         end;
  1738.                         if err <> noErr then begin
  1739.                             err := CreateOTEndpoint(lp^.ep, OTCreateConfiguration( "tcp" ), nil, lp);
  1740.                         end;
  1741.                         if err = noErr then begin
  1742.                             err := BindOTListener(lp^.ep, localport, 99);
  1743.                             if err <> noErr then begin
  1744.                                 junk := OTCloseProvider(lp^.ep);
  1745.                             end;
  1746.                         end;
  1747.                         if err <> noErr then begin
  1748.                             MDisposeHandle(lp^.sequences);
  1749.                         end;
  1750.                     end;
  1751.                 end else begin
  1752.                     lp^.mt_listeners_count := listeners;
  1753.                     lp^.mt_buffer_size := buffer_size;
  1754.                     for i := 1 to lp^.mt_listeners_count do begin
  1755.                         lp^.mt_listeners[i] := nil;
  1756.                     end;
  1757.                 end;
  1758.             end;
  1759.         end;
  1760.         if err <> noErr then begin
  1761.             MDisposePtr(lp);
  1762.         end;
  1763.         token := Ptr(lp);
  1764.         TransportListen := err;
  1765.     end;
  1766. {    
  1767.     procedure ReopenTransportListener(lp:TransportListenRecordPtr);
  1768.         var
  1769.             err, junk: OSErr;
  1770.             newep: EndpointRef;
  1771.     begin
  1772.         err := CreateOTEndpoint(newep, nil, lp);
  1773.         if err = noErr then begin
  1774.             err := BindOTListener(newep, lp^.localport, 99);
  1775.             if err <> noErr then begin
  1776.                 junk := OTCloseProvider(newep);
  1777.             end;
  1778.         end;
  1779.         if err = noErr then begin
  1780.             junk := OTCloseProvider(lp^.ep);
  1781.             lp^.ep := newep;
  1782.         end;
  1783.     end;
  1784. }    
  1785.     function TransportGetListenerConnectionOT(lp:TransportListenRecordPtr; var tref:TransportRef):OSStatus;
  1786.         function CountSequences: longint;
  1787.         begin
  1788.             CountSequences := MGetHandleSize(Handle(lp^.sequences)) div SizeOf(OTSequence);
  1789.         end;
  1790.         
  1791.         procedure DelSequence(sequence: OTSequence);
  1792.             var
  1793.                 i: longint;
  1794.         begin
  1795.             for i := 0 to CountSequences - 1 do begin
  1796.                 if lp^.sequences^^[i] = sequence then begin
  1797.                     MMungerDelete(Handle(lp^.sequences), i * SizeOf(OTSequence), SizeOf(OTSequence));
  1798.                     Exit(DelSequence);
  1799.                 end;
  1800.             end;
  1801.             Assert( false );
  1802.         end;
  1803.         label
  1804.             1;
  1805.         var
  1806.             err: OSStatus;
  1807.             result: OTResult;
  1808.             rcvCall:TCall;
  1809.             rcvsin:InetAddress;
  1810.             btp:TransportRecordPtr;
  1811.             discon: TDiscon;
  1812.             sequence: OTSequence;
  1813.     begin
  1814.         1:
  1815.         repeat
  1816.             MZero(@rcvCall, sizeof(rcvCall));
  1817.             OTInitNetbuf(rcvCall.addr, @rcvsin, sizeof(InetAddress));
  1818.             result := OTListen(lp^.ep, @rcvCall);
  1819.             if result = noErr then begin
  1820.                 sequence := rcvCall.sequence;
  1821.                 result := PtrAndHand(@sequence, Handle(lp^.sequences), SizeOf(sequence));
  1822.             end else if result = kOTLookErr then begin
  1823.                 MZero(@discon, sizeof(discon));
  1824.                 result := OTRcvDisconnect(lp^.ep, @discon);
  1825.                 if result = noErr then begin
  1826.                     DelSequence(discon.sequence);
  1827.                 end;
  1828. {                end else if result = kOTOutStateErr then begin
  1829.                 ReopenTransportListener( lp );}
  1830.             end;
  1831.         until result <> noErr;
  1832.         if result <> kOTNoDataErr then begin
  1833.             err := result;
  1834.         end else begin
  1835.             if CountSequences = 0 then begin
  1836.                 err := inProgress;
  1837.             end else begin
  1838.                 err := TransportCreate(btp, 0);
  1839.                 if err = noErr then begin
  1840.                     tref := TransportRef(btp);
  1841.                     btp^.started_opening := true;
  1842.                     MZero(@rcvCall, sizeof(rcvCall));
  1843.                     rcvCall.sequence := lp^.sequences^^[0];
  1844.                     err := OTAccept(lp^.ep, btp^.ep, @rcvCall);
  1845.                     if err = kOTLookErr then begin
  1846.                         TransportDestroy(tref);
  1847.                         goto 1;
  1848.                     end else begin
  1849.                         MMungerDelete(Handle(lp^.sequences), 0, SizeOf(OTSequence));
  1850.                     end;
  1851.                     if err = noErr then begin
  1852.                         err:=OTSetAsynchronous(btp^.ep);
  1853.                     end;
  1854.                     if err <> noErr then begin
  1855.                         TransportDestroy(tref);
  1856.                     end;
  1857.                 end;
  1858.             end;
  1859.         end;
  1860.         TransportGetListenerConnectionOT := err;
  1861.     end;
  1862.     
  1863.  
  1864. (*    function CreateOTListenerEndpoint( var ep: EndpointRef; var localport: ipPort; context: univ Ptr; reuse: boolean ): OSStatus;
  1865.         var
  1866.             err, junk: OSStatus;
  1867.     begin
  1868.         if ot_version >= kOTTILISTENVersion then begin
  1869.             err := CreateOTEndpoint( ep, OTCreateConfiguration( "tilisten, tcp" ), nil, context );
  1870.         end else begin
  1871.             err := -1;
  1872.         end;
  1873.         if err <> noErr then begin
  1874.             err := CreateOTEndpoint( ep, OTCreateConfiguration( "tcp" ), nil, context );
  1875.         end;
  1876.         if err = noErr then begin
  1877.             if reuse then begin
  1878.                 junk := SetReuseAddr( ep );
  1879.             end;
  1880.             err := BindOTListener( ep, localport, 99 );
  1881.             if err <> noErr then begin
  1882.                 MCloseProvider( ep );
  1883.             end;
  1884.         end;
  1885.         CreateOTListenerEndpoint := err;
  1886.     end;
  1887.     
  1888.     function TransportListen(var token:Ptr; localport:ipPort; listeners:integer; buffer_size:longint):OSStatus;
  1889.         var
  1890.             lp:TransportListenRecordPtr;
  1891.             err:OSStatus;
  1892.             i:integer;
  1893.     begin
  1894.         lp := nil;
  1895.         err := OpenTransportSystem;
  1896.         if err = noErr then begin
  1897.             err := MNewPtr(lp, SizeOf(TransportListenRecord));
  1898.             if err = noErr then begin
  1899.                 lp^.localport := localport;
  1900.                 if have_OT then begin
  1901.                     err := MNewHandle(lp^.sequences, 0);
  1902.                     if err = noErr then begin
  1903.                         err := CreateOTListenerEndpoint( lp^.ep, localport, lp, false );
  1904.                         if err <> noErr then begin
  1905.                             MDisposeHandle(lp^.sequences);
  1906.                         end;
  1907.                     end;
  1908.                 end else begin
  1909.                     lp^.mt_listeners_count := listeners;
  1910.                     lp^.mt_buffer_size := buffer_size;
  1911.                     for i := 1 to lp^.mt_listeners_count do begin
  1912.                         lp^.mt_listeners[i] := nil;
  1913.                     end;
  1914.                 end;
  1915.             end;
  1916.         end;
  1917.         if err <> noErr then begin
  1918.             MDisposePtr(lp);
  1919.         end;
  1920.         token := Ptr(lp);
  1921.         TransportListen := err;
  1922.     end;
  1923.  
  1924.     procedure ReopenTransportListener(lp:TransportListenRecordPtr);
  1925.         var
  1926.             err: OSErr;
  1927.             newep: EndpointRef;
  1928.     begin
  1929.         err := CreateOTListenerEndpoint( newep, lp^.localport, lp, true );
  1930.         if err = noErr then begin
  1931.             MCloseProvider( lp^.ep );
  1932.             lp^.ep := newep;
  1933.             SetHandleSize( Handle(lp^.sequences), 0 );
  1934.         end;
  1935.     end;
  1936.  
  1937.     var
  1938.         next_listener_connection: TransportRecordPtr;
  1939.         
  1940.     procedure ListenerNotifier( up: boolean );
  1941.     begin
  1942.         if not up & (next_listener_connection <> nil) then begin
  1943.             TransportDestroy(TransportRef(next_listener_connection));
  1944.         end;
  1945.     end;
  1946.     
  1947.     function TransportGetListenerConnectionOT(lp:TransportListenRecordPtr; var tref:TransportRef):OSStatus;
  1948.  
  1949.         procedure DoRcvDisconnect( ep: EndpointRef );
  1950.             var
  1951.                 junk: OSStatus;
  1952.         begin
  1953.             junk := OTRcvDisconnect( ep, nil );
  1954.             Assert( junk = noErr );
  1955.         end;
  1956.         
  1957.         procedure HandleLookError( err: OSStatus; ep: EndpointRef );
  1958.             var
  1959.                 result: OTResult;
  1960.         begin
  1961.             if err <> noErr then begin
  1962.                 result := OTLook( ep );
  1963.                 if (err = kOTLookErr) & (result = T_DISCONNECT) then begin
  1964.                     DoRcvDisconnect( lp^.ep );
  1965.                 end;
  1966.             end;
  1967.         end;
  1968.  
  1969.         var
  1970.             err: OSStatus;
  1971.             call:TCall;
  1972.             caddr:InetAddress;
  1973.     begin
  1974.         err := noErr;
  1975.         if next_listener_connection = nil then begin
  1976.             err := TransportCreate(next_listener_connection, 0);
  1977.         end;
  1978.         if err = noErr then begin
  1979.             MZero( @call, sizeof(call) );
  1980.             OTInitNetbuf( call.addr, @caddr, sizeof(caddr) );
  1981.             err := OTListen( lp^.ep, @call );
  1982.             HandleLookError( err, lp^.ep );
  1983.             if err = kOTNoDataErr then begin
  1984.                 err := inProgress;
  1985.             end else if err = noErr then begin
  1986.                 err := OTAccept( lp^.ep, next_listener_connection^.ep, @call );
  1987.                 HandleLookError( err, lp^.ep );
  1988.                 if err = noErr then begin
  1989.                     tref := TransportRef(next_listener_connection);
  1990.                     next_listener_connection^.started_opening := true;
  1991.                     err:=OTSetAsynchronous(next_listener_connection^.ep);
  1992.                     Assert( err = noErr );
  1993.                     next_listener_connection := nil;
  1994.                 end;
  1995.             end;
  1996.         end;
  1997.         TransportGetListenerConnectionOT := err;
  1998.     end;
  1999.         
  2000.  
  2001.     function TransportGetListenerConnectionOT(lp:TransportListenRecordPtr; var tref:TransportRef):OSStatus;
  2002.         function CountSequences: longint;
  2003.         begin
  2004.             CountSequences := MGetHandleSize(Handle(lp^.sequences)) div SizeOf(OTSequence);
  2005.         end;
  2006.         
  2007.         procedure DelSequence(sequence: OTSequence);
  2008.             var
  2009.                 i: longint;
  2010.         begin
  2011.             for i := 0 to CountSequences - 1 do begin
  2012.                 if lp^.sequences^^[i] = sequence then begin
  2013.                     MMungerDelete(Handle(lp^.sequences), i * SizeOf(OTSequence), SizeOf(OTSequence));
  2014.                     Exit(DelSequence);
  2015.                 end;
  2016.             end;
  2017.             Assert( false );
  2018.         end;
  2019.         label
  2020.             1;
  2021.         var
  2022.             err: OSStatus;
  2023.             result: OTResult;
  2024.             rcvCall:TCall;
  2025.             rcvsin:InetAddress;
  2026.             btp:TransportRecordPtr;
  2027.             discon: TDiscon;
  2028.             sequence: OTSequence;
  2029.     begin
  2030.         1:
  2031.         repeat
  2032.             MZero(@rcvCall, sizeof(rcvCall));
  2033.             OTInitNetbuf(rcvCall.addr, @rcvsin, sizeof(InetAddress));
  2034.             err := OTListen(lp^.ep, @rcvCall);
  2035.             if err = noErr then begin
  2036.                 sequence := rcvCall.sequence;
  2037.                 err := PtrAndHand(@sequence, Handle(lp^.sequences), SizeOf(sequence));
  2038.                 Assert( err = noErr );
  2039.             end else if err <> kOTNoDataErr then begin
  2040.                 result := OTLook( lp^.ep );
  2041.                 if result = T_DISCONNECT then begin
  2042.                     MZero(@discon, sizeof(discon));
  2043.                     result := OTRcvDisconnect(lp^.ep, @discon);
  2044.                     if result = noErr then begin
  2045.                         DelSequence(discon.sequence);
  2046.                     end else begin
  2047. {$ifc do_debug}
  2048.                         Assert( false );
  2049.                         result := OTGetEndpointState(lp^.ep);
  2050. {$endc}
  2051.                         ReopenTransportListener( lp );
  2052.                     end;
  2053.                 end else begin
  2054. {$ifc do_debug}
  2055.                     Assert( false );
  2056.                     result := OTGetEndpointState(lp^.ep);
  2057. {$endc}
  2058.                     ReopenTransportListener( lp );
  2059.                 end;
  2060. {                end else if err = kOTOutStateErr then begin
  2061.                 ReopenTransportListener( lp );}
  2062.             end;
  2063.         until err <> noErr;
  2064.         if CountSequences > 0 then begin
  2065.             err := TransportCreate(btp, 0);
  2066.             if err = noErr then begin
  2067.                 tref := TransportRef(btp);
  2068.                 btp^.started_opening := true;
  2069.                 MZero(@rcvCall, sizeof(rcvCall));
  2070.                 rcvCall.sequence := lp^.sequences^^[0];
  2071.                 err := OTAccept(lp^.ep, btp^.ep, @rcvCall);
  2072.                 if err = kOTLookErr then begin
  2073.                     TransportDestroy(tref);
  2074.                     goto 1;
  2075.                 end else begin
  2076.                     MMungerDelete(Handle(lp^.sequences), 0, SizeOf(OTSequence));
  2077.                 end;
  2078.                 if err = noErr then begin
  2079.                     err:=OTSetAsynchronous(btp^.ep);
  2080.                 end;
  2081.                 if err <> noErr then begin
  2082.                     TransportDestroy(tref);
  2083.                 end;
  2084.             end;
  2085.         end else if err = kOTNoDataErr then begin
  2086.             err := inProgress;
  2087.         end else begin
  2088. {$ifc do_debug}
  2089.             Assert( false );
  2090.             result := OTGetEndpointState(lp^.ep);
  2091. {$endc}
  2092.             ReopenTransportListener( lp );
  2093.         end;
  2094.         TransportGetListenerConnectionOT := err;
  2095.     end;
  2096. *)
  2097.  
  2098.     function TransportGetListenerConnection(token:Ptr; var tref:TransportRef):OSStatus;
  2099.         var
  2100.             err, result:OSStatus;
  2101.             lp:TransportListenRecordPtr;
  2102.             i:integer;
  2103.     begin
  2104.         lp := TransportListenRecordPtr(token);
  2105.         if lp = nil then begin
  2106.             err := -900007;
  2107.         end else begin
  2108.             err := TransportSystemIsAlive;
  2109.             if err = noErr then begin
  2110.                 err := inProgress;
  2111.                 if have_OT then begin
  2112.                     err := TransportGetListenerConnectionOT(lp, tref);
  2113.                 end else begin
  2114.                     for i := 1 to lp^.mt_listeners_count do begin
  2115.                         if (lp^.mt_listeners[i] = nil) & EnoughSpace(100000, 70000) then begin
  2116.                             err := TransportOpenPassiveConnection(lp^.mt_listeners[i], lp^.localport, lp^.mt_buffer_size);
  2117.                             leave; { only create one listener, that allows the listeners to be shared a bit better }
  2118.                         end;
  2119.                     end;
  2120.  
  2121.                     err := inProgress;
  2122.                     for i := 1 to lp^.mt_listeners_count do begin
  2123.                         if (lp^.mt_listeners[i] <> nil) then begin
  2124.                             Assert(ValidTransport(lp^.mt_listeners[i]));
  2125.                             TransportGetOpenResult(lp^.mt_listeners[i], result);
  2126.                             case result of
  2127.                                 inProgress: begin
  2128.                                 end;
  2129.                                 noErr:begin
  2130.                                     tref := lp^.mt_listeners[i];
  2131.                                     lp^.mt_listeners[i] := nil;
  2132.                                     err := noErr;
  2133.                                     leave;
  2134.                                 end;
  2135.                                 otherwise begin
  2136.                                     TransportDestroy(lp^.mt_listeners[i]);
  2137.                                 end;
  2138.                             end;
  2139.                         end;
  2140.                     end;
  2141.                 end;
  2142.             end;
  2143.         end;
  2144.         if err <> noErr then begin
  2145.             tref := nil;
  2146.         end;
  2147.         TransportGetListenerConnection := err;
  2148.     end;
  2149.     
  2150.     procedure TransportDestroyListener(var token:Ptr);
  2151.         var
  2152.             err:OSStatus;
  2153.             lp:TransportListenRecordPtr;
  2154.             i:integer;
  2155.     begin
  2156.         err := TransportSystemIsAlive;
  2157.         if err = noErr then begin
  2158.             lp := TransportListenRecordPtr(token);
  2159.             if lp <> nil then begin
  2160.                 if have_OT then begin
  2161.                     MCloseProvider(lp^.ep);
  2162.                     MDisposeHandle(lp^.sequences);
  2163.                 end else begin
  2164.                     for i := 1 to lp^.mt_listeners_count do begin
  2165.                         TransportDestroy(lp^.mt_listeners[i]);
  2166.                     end;
  2167.                     lp^.mt_listeners_count := 0;
  2168.                 end;
  2169.                 MDisposePtr(token);
  2170.             end;
  2171.         end;
  2172.     end;
  2173.  
  2174.     function CreateOTUDPEndpoint(var ep:EndpointRef; proc:OTNotifyProcPtr; var localport: ipPort; context:univ Ptr):OSErr;
  2175.         var
  2176.             err: OSStatus;
  2177.             reqsin, retsin:InetAddress;
  2178.             req, ret:TBind;
  2179.     begin
  2180.         ep:=OTOpenEndpoint(OTCreateConfiguration("udp"),0,nil,err);
  2181.         if (err = noErr) & (proc <> nil) then begin
  2182.             err:=OTInstallNotifier(ep, proc, context);
  2183.         end;
  2184.  
  2185.         if err = noErr then begin
  2186.             if localport <> 0 then begin
  2187.                 OTInitInetAddress(reqsin, localport, 0);
  2188.                 OTInitNetbuf(req.addr, @reqsin, sizeof(InetAddress));
  2189.             end else begin
  2190.                 OTInitNetbuf(req.addr, nil, 0);
  2191.             end;
  2192.             req.qlen := 1;
  2193.             
  2194.             MZero(@ret, sizeof(ret));
  2195.             OTInitNetbuf(ret.addr, @retsin, sizeof(InetAddress));
  2196.             err := OTBind(ep, @req, @ret);
  2197.             localport := retsin.fPort;
  2198.         end;
  2199.         if (err = noErr) & (localport <> 0) & (localport <> retsin.fPort) then begin
  2200.             err := couldNotGetRequestedPortErr;
  2201.         end;
  2202.         if err = noErr then begin
  2203.             err:=OTSetNonBlocking(ep);
  2204.         end;
  2205.         if err <> noErr then begin
  2206.             MCloseProvider(ep);
  2207.         end;
  2208.         CreateOTUDPEndpoint := err;
  2209.     end;
  2210.     
  2211.     procedure UDPEventHandlerOT (tup: TransportUDPRecordPtr; event: OTEventCode; result: OTResult; cookie: univ Ptr);
  2212.     begin
  2213. {$unused(cookie, result)}
  2214.         case event of
  2215.             T_DATA: begin
  2216.                 tup^.packets_available := true;
  2217.             end;
  2218.             otherwise
  2219.                 ;
  2220.         end;
  2221.     end;
  2222.  
  2223.     function TransportUDPOpenPort(var tref: TransportUDPRef; var localport: ipPort; buffer_size:longint): OSStatus;
  2224.         var
  2225.             err:OSStatus;
  2226.             tup: TransportUDPRecordPtr;
  2227.     begin
  2228.         buffer_size := Pin(10240, buffer_size, 64512);
  2229.         tup := nil;
  2230.         err := OpenTransportSystem;
  2231.         if err = noErr then begin
  2232.             err := MNewPtr(tup, SizeOf(TransportUDPRecord));
  2233.             if err = noErr then begin
  2234.                 if have_OT then begin
  2235.                     tup^.packets_available := false;
  2236.                     err := CreateOTUDPEndpoint(tup^.ep, @UDPEventHandlerOT, localport, tup);
  2237.                 end else begin
  2238.                     tup^.stream := nil;
  2239.                     err := MNewPtr(tup^.stream_buffer, buffer_size);
  2240.                     if err = noErr then begin
  2241.                         err := MTUDPCreate(tup^.stream, localport, @tup^.outstanding_packets, tup^.stream_buffer, buffer_size);
  2242.                     end;
  2243.                 end;
  2244.                 if err <> noErr then begin
  2245.                     TransportUDPDestroy(TransportUDPRef(tup));
  2246.                 end;
  2247.             end;
  2248.         end;
  2249.         tref := TransportUDPRef(tup);
  2250.         TransportUDPOpenPort := err;
  2251.     end;
  2252.     
  2253.     procedure TransportUDPDestroy (var tref: TransportUDPRef);
  2254.         var
  2255.             err: OSStatus;
  2256.             tup: TransportUDPRecordPtr;
  2257.     begin
  2258.         err := noErr;
  2259.         tup := TransportUDPRecordPtr(tref);
  2260.         if tup <> nil then begin
  2261.             if  TransportSystemIsAlive = noErr then begin
  2262.                 if have_OT then begin
  2263.                     if tup^.ep <> nil then begin
  2264.                         MCloseProvider(tup^.ep);
  2265.                     end;
  2266.                 end else begin
  2267.                     if tup^.stream <> nil then begin
  2268.                         err := MTUDPRelease(tup^.stream);
  2269.                     end;
  2270.                     MDisposePtr(tup^.stream_buffer);
  2271.                 end;
  2272.             end;
  2273.             MDisposePtr(tup);
  2274.             tref := nil;
  2275.         end;
  2276.     end;
  2277.     
  2278.     const
  2279.         max_udp_datalen = 2048;
  2280.         
  2281.     function TransportUDPDatagramsAvailable (tref: TransportUDPRef): longint;
  2282.         var
  2283.             tup: TransportUDPRecordPtr;
  2284.     begin
  2285. Assert( false ); { check tup^.packets_available code }
  2286.  
  2287.         tup := TransportUDPRecordPtr(tref);
  2288.         Assert(tup <> nil);
  2289.         if have_OT then begin
  2290.             TransportUDPDatagramsAvailable := Choose( tup^.packets_available, 1, 0 );
  2291.         end else begin
  2292.             TransportUDPDatagramsAvailable := tup^.outstanding_packets;
  2293.         end;
  2294.     end;
  2295.  
  2296.     function TransportUDPRead (tref: TransportUDPRef; var remoteip: longint; var remoteport: ipPort;
  2297.                                     var datap: Ptr; var datalen: integer): OSStatus;
  2298.         var
  2299.             err:OSStatus;
  2300.             tup: TransportUDPRecordPtr;
  2301.             udata:TUnitData;
  2302.             flags: OTFlags;
  2303.             srcsin: InetAddress;
  2304.     begin
  2305.         tup := TransportUDPRecordPtr(tref);
  2306.         Assert(tup <> nil);
  2307.         err := TransportSystemIsAlive;
  2308.         if  err = noErr then begin
  2309.             if have_OT then begin
  2310.                 err := MNewPtr(datap, max_udp_datalen);
  2311.                 if err = noErr then begin
  2312.                     MZero(@udata, SizeOf(udata));
  2313.                     OTInitNetbuf(udata.addr, @srcsin, SizeOf(srcsin));
  2314.                     OTInitNetbuf(udata.udata, datap, max_udp_datalen);
  2315.                     tup^.packets_available := false;
  2316.                     err := OTLFRcvUData(tup^.ep,udata, flags);
  2317.                     if err = noErr then begin
  2318.                         tup^.packets_available := true;
  2319.                         datalen := udata.udata.len;
  2320.                         remoteip := srcsin.fHost;
  2321.                         remoteport := srcsin.fPort;
  2322.                     end;
  2323.                 end;
  2324.                 if err <> noErr then begin
  2325.                     MDisposePtr(datap);
  2326.                 end;
  2327.             end else begin
  2328.                 err := MTUDPRead(tup^.stream, @tup^.outstanding_packets, remoteip, remoteport, datap, datalen);
  2329.             end;
  2330.         end;
  2331.         TransportUDPRead := err;
  2332.     end;
  2333.  
  2334.     function TransportUDPReturnBuffer (tref: TransportUDPRef; datap: Ptr): OSStatus;
  2335.         var
  2336.             err:OSStatus;
  2337.             tup: TransportUDPRecordPtr;
  2338.     begin
  2339.         err := noErr;
  2340.         tup := TransportUDPRecordPtr(tref);
  2341.         Assert(tup <> nil);
  2342.         if tup <> nil then begin
  2343.             if have_OT then begin
  2344.                 MDisposePtr(datap);
  2345.             end else begin
  2346.                 err := MTUDPReturnBuffer(tup^.stream, datap);
  2347.             end;
  2348.         end;
  2349.         TransportUDPReturnBuffer := err;
  2350.     end;
  2351.  
  2352.     function TransportUDPWrite (tref: TransportUDPRef; remoteip: longint; remoteport: ipPort;
  2353.                                     datap: Ptr; datalen: integer; checksum: boolean): OSStatus;
  2354.         var
  2355.             err:OSStatus;
  2356.             tup: TransportUDPRecordPtr;
  2357.             udata:TUnitData;
  2358.             destsin: InetAddress;
  2359.             
  2360.             junk_result: OTResult;
  2361.     begin
  2362.         err := noErr;
  2363.         tup := TransportUDPRecordPtr(tref);
  2364.         Assert(tup <> nil);
  2365.         if tup <> nil then begin
  2366.             err := TransportSystemIsAlive;
  2367.             if  err = noErr then begin
  2368.                 if have_OT then begin
  2369.                     MZero(@udata, SizeOf(udata));
  2370.                     OTInitInetAddress(destsin, remoteport, remoteip);
  2371.                     OTInitNetbuf(udata.addr, @destsin, SizeOf(destsin));
  2372.                     OTInitNetbuf(udata.udata, datap, datalen);
  2373.                     err := OTLFSndUData(tup^.ep,udata);
  2374.                     
  2375.                     if err = kOTLookErr then begin
  2376.                     Assert( false );
  2377.                     junk_result := OTLook( tup^.ep );
  2378.                     end;
  2379.                 end else begin
  2380.                     err := MTUDPWrite(tup^.stream, remoteip, remoteport, datap, datalen, checksum);
  2381.                 end;
  2382.             end;
  2383.         end;
  2384.         TransportUDPWrite := err;
  2385.     end;
  2386.  
  2387.     var
  2388.         rawip: EndpointRef;
  2389.         icmps: QHdr;
  2390.         delayed_close_time: longint;
  2391.         ping_id: UInt16;
  2392.         ping_sequence: UInt16;
  2393.     
  2394. {$PUSH}
  2395. {$ALIGN MAC68K}
  2396.     type
  2397.         PingMessage = packed record
  2398.                 typ: UInt8;
  2399.                 code: UInt8;
  2400.                 checksum: UInt16;
  2401.                 id: UInt16;
  2402.                 sequence: UInt16;
  2403.             end;
  2404.         PingMessagePtr = ^PingMessage;
  2405. {$ALIGN RESET}
  2406. {$POP}
  2407.  
  2408.     type
  2409.         TransportSendPingData = record
  2410.                 completion: PingCompletionProc; { MacTCP } { must be first entry in record! }
  2411.                 qlink: TransportSendPingDataPtr; { OT }
  2412.                 result: OSStatus;
  2413.                 results: TransportPingResults;
  2414.                 { OT only }
  2415.                 id: UInt16;
  2416.                 sequence: UInt16;
  2417.                 timeout: longint;
  2418.                 dead: boolean;
  2419.                 start_time: UnsignedWide;
  2420.             end;
  2421.         TransportSendPingDataPtr = ^TransportSendPingData;
  2422.     
  2423.     procedure EnquePing( ted: TransportSendPingDataPtr );
  2424.     begin
  2425.         Assert( ted <> nil );
  2426.         Enqueue( @ted^.qlink, @icmps );
  2427.     end;
  2428.  
  2429.     procedure DequePing( ted: TransportSendPingDataPtr );
  2430.         var
  2431.             junk: OSErr;
  2432.     begin
  2433.         Assert( ted <> nil );
  2434.         junk := Dequeue( @ted^.qlink, @icmps );
  2435.         Assert( junk = noErr );
  2436.         delayed_close_time := TickCount + 30 * second_in_ticks;
  2437.     end;
  2438.     
  2439.     function OpenPing: OSErr;
  2440.         var
  2441.             err: OSStatus;
  2442.             info: TEndpointInfo;
  2443.     begin
  2444.         delayed_close_time := TickCount + 30 * second_in_ticks;
  2445.         err := noErr;
  2446.         if rawip = nil then begin
  2447.             rawip := OTOpenEndpoint( OTCreateConfiguration( "rawip" ), 0, @info, err );
  2448.             if err = noErr then begin
  2449.                 err := OTBind( rawip, nil, nil );
  2450.                 if err = noErr then begin
  2451.                     err := OTSetNonBlocking( rawip );
  2452.                 end;
  2453.                 if err <> noErr then begin
  2454.                     MCloseProvider( rawip );
  2455.                 end;
  2456.             end;
  2457.         end;
  2458.         OpenPing := err;
  2459.     end;
  2460.     
  2461.     procedure CorrectTed( var ted: TransportSendPingDataPtr );
  2462.     begin
  2463.         if ted <> nil then begin
  2464.             OffsetPtr( ted, SubPtrPtr( ted, @ted^.qlink ) );
  2465.         end;
  2466.     end;
  2467.     
  2468.     procedure NextPing( var ted: TransportSendPingDataPtr );
  2469.     begin
  2470.         if ted = nil then begin
  2471.             ted := TransportSendPingDataPtr(icmps.qHead);
  2472.         end else begin
  2473.             ted := ted^.qlink;
  2474.         end;
  2475.         CorrectTed( ted );
  2476.     end;
  2477.     
  2478.     procedure ClosePing( error: OSStatus );
  2479.         var
  2480.             ted: TransportSendPingDataPtr;
  2481.     begin
  2482.         ted := nil;
  2483.         NextPing( ted );
  2484.         while ( ted <> nil ) do begin
  2485.             if ted^.result = inProgress then begin
  2486.                 if have_OT then begin
  2487.                     ted^.dead := true;
  2488.                 end else begin
  2489.                     ted^.result := error;
  2490.                 end;
  2491.             end;
  2492.             NextPing( ted );
  2493.         end;
  2494.         if (rawip <> nil) then begin
  2495.             MCloseProvider( rawip );
  2496.         end;
  2497.     end;
  2498.     
  2499.     procedure CheckClosePing;
  2500.     begin
  2501.         if (rawip <> nil) & (icmps.qHead = nil) & (TickCount > delayed_close_time) then begin
  2502.             ClosePing( -900009 );
  2503.         end;
  2504.     end;
  2505.  
  2506.     procedure InitPing;
  2507.         var
  2508.             date: UInt32;
  2509.     begin
  2510.         rawip := nil;
  2511.         icmps.qHead := nil;
  2512.         icmps.qTail := nil;
  2513.         ping_id := 1000 + band(SInt32(Ord4(TickCount)), $3FFF);
  2514.         GetDateTime( date );
  2515.         ping_sequence := 1000 + band(date, $3FFF);
  2516.     end;
  2517.     
  2518.     procedure PingNotifier( up: Boolean );
  2519.     begin
  2520.         if not up then begin
  2521.             ClosePing( -900020 );
  2522.         end;
  2523.     end;
  2524.     
  2525.     procedure Checksum( pm: PingMessagePtr; len: longint );
  2526.         var
  2527.             sum: longint;
  2528.             p: unsignedwordP;
  2529.             i: longint;
  2530.     begin
  2531.         pm^.checksum := 0;
  2532.         p := unsignedwordP(pm);
  2533.         sum := 0;
  2534.         for i := 1 to len div 2 do begin
  2535.             sum := sum + p^;
  2536.             OffsetPtr( p, 2 );
  2537.         end;
  2538.         if odd(len) then begin
  2539.             sum := sum +bsl(band(integer(p^), $000000FF),8);
  2540.         end;
  2541.         sum := bsr(sum, 16) + band(sum, $0000FFFF); { should bsr be arithmetic or logical??? }
  2542.         sum := sum + bsr(sum, 16);
  2543.         pm^.checksum := bnot( sum );
  2544.     end;
  2545.     
  2546.     function OTSendPing( remoteip: longint; id, sequence: UInt16; buffer: Ptr; bufferlen: longint ): OSStatus;
  2547.         var
  2548.             err: OSStatus;
  2549.             dest: InetAddress;
  2550.             udata: TUnitData;
  2551.             packet: Ptr;
  2552.             pm: PingMessagePtr;
  2553.             packet_len: longint;
  2554.     begin
  2555.         packet_len := SizeOf(PingMessage) + bufferlen;
  2556.         packet := NewPtr( packet_len );
  2557.         err := MemError;
  2558.         if err = noErr then begin
  2559.             pm := PingMessagePtr(packet);
  2560.             pm^.typ := 8;
  2561.             pm^.code := 0;
  2562.             pm^.id := id;
  2563.             pm^.sequence := sequence;
  2564.             BlockMoveData( buffer, AddPtrLong( pm, SizeOf(PingMessage) ), bufferlen );
  2565.             Checksum( pm,packet_len );
  2566.  
  2567.             OTInitInetAddress( dest, 0, remoteip );
  2568.             udata.addr.buf := @dest;
  2569.             udata.addr.len := SizeOf(dest);
  2570.             udata.opt.buf := nil;
  2571.             udata.opt.len := 0;
  2572.             udata.udata.buf := packet;
  2573.             udata.udata.len := packet_len;
  2574.             err := OTLFSndUData( rawip, udata );
  2575.             
  2576.             DisposePtr(packet);
  2577.         end;
  2578.         OTSendPing := err;
  2579.     end;
  2580.     
  2581. {$PUSH}
  2582. {$ALIGN MAC68K}
  2583.     type
  2584.         IPPacket = packed record
  2585.             versize: UInt8;
  2586.             junk1: UInt8;
  2587.             total_length: UInt16; { broken in OT 1.1 }
  2588.             ident: UInt16;
  2589.             flags: UInt16;
  2590.             ttl: UInt8;
  2591.             protocol: UInt8; { ICMP = 1 }
  2592.             checksum: UInt16;
  2593.             srcIP: ipAddr;
  2594.             dstIP: ipAddr;
  2595.             { options }
  2596.         end;
  2597.         IPPacketPtr = ^IPPacket;
  2598. {$ALIGN RESET}
  2599. {$POP}
  2600.         
  2601.     function IsPingResponse( packet: Ptr; packet_len: longint; var remotehost: ipAddr; var pmp: PingMessagePtr; var ping_len: longint ): boolean;
  2602.         var
  2603.             ipp: IPPacketPtr;
  2604.             header_len: longint;
  2605.     begin
  2606.         IsPingResponse := false;
  2607.         if packet_len > 20 then begin
  2608.             ipp := IPPacketPtr(packet);
  2609.             if (band(ipp^.versize, $00F0) = $0040) then begin
  2610.                 header_len := band(ipp^.versize, $000F) * 4;
  2611.                 if (header_len >= 20) & (packet_len >= header_len + SizeOf(PingMessage)) then begin
  2612.                     if (ipp^.protocol = 1) then begin
  2613.                         pmp := PingMessagePtr(AddPtrLong( ipp, header_len ));
  2614.                         if pmp^.typ = 0 then begin { ICMP response }
  2615.                             { Check checksum? }
  2616.                             IsPingResponse := true;
  2617.                             ping_len := packet_len - header_len;
  2618.                             remotehost := ipp^.srcIP;
  2619.                         end;
  2620.                     end;
  2621.                 end;
  2622.             end;
  2623.         end;
  2624.     end;
  2625.     
  2626.     function FindPing( id, sequence: UInt16; var ted: TransportSendPingDataPtr ): boolean;
  2627.     begin
  2628.         ted := nil;
  2629.         NextPing( ted );
  2630.         while ted <> nil do begin
  2631.             if (ted^.id = id) & (ted^.sequence = sequence) then begin
  2632.                 leave;
  2633.             end;
  2634.             NextPing( ted );
  2635.         end;
  2636.         FindPing := ted <> nil;
  2637.     end;
  2638.  
  2639.     function ValidPing( check_ted: TransportSendPingDataPtr ): boolean;
  2640.         var
  2641.             ted: TransportSendPingDataPtr;
  2642.     begin
  2643.         ted := nil;
  2644.         NextPing( ted );
  2645.         while ted <> nil do begin
  2646.             if ted = check_ted then begin
  2647.                 leave;
  2648.             end;
  2649.             NextPing( ted );
  2650.         end;
  2651.         ValidPing := ted <> nil;
  2652.     end;
  2653.     
  2654.     procedure KillOTPing( var ted: TransportSendPingDataPtr );
  2655.     begin
  2656.         DequePing( ted );
  2657.         MDisposePtr( ted^.results.data );
  2658.         MDisposePtr( ted );
  2659.     end;
  2660.     
  2661.     procedure KillDeadPings;
  2662.         var
  2663.             ted: TransportSendPingDataPtr;
  2664.     begin
  2665.         ted := nil;
  2666.         NextPing( ted );
  2667.         while ted <> nil do begin
  2668.             if ted^.dead & (ted^.result <> inProgress) then begin
  2669.                 MDisposePtr( ted^.results.data );
  2670.                 DequePing( ted );
  2671.                 MDisposePtr(ted );
  2672.                 leave; { just do one - if we do more, we have to fix the following call to NextPing }
  2673.             end;
  2674.             if have_OT then begin
  2675.                 if TickCount > ted^.timeout then begin
  2676.                     ted^.result := icmpEchoTimeoutErr;
  2677. {                    KillOTPing( ted );
  2678.                     leave;}
  2679.                 end;
  2680.             end;
  2681.             NextPing( ted );
  2682.         end;
  2683.     end;
  2684.     
  2685.     procedure ReadPingResponse;
  2686.         var
  2687.             err: OSStatus;
  2688.             src: InetAddress;
  2689.             udata: TUnitData;
  2690.             flags: OTFlags;
  2691.             pmp: PingMessagePtr;
  2692.             ping_len: longint;
  2693.             ted: TransportSendPingDataPtr;
  2694.             remotehost: ipAddr;
  2695.             data_len: longint;
  2696.             finish_time: UnsignedWide;
  2697.     begin
  2698.         if rawip <> nil then begin
  2699.             udata.addr.buf := @src;
  2700.             udata.addr.maxlen := SizeOf(src);
  2701.             udata.opt.buf := nil;
  2702.             udata.opt.maxlen := 0;
  2703.             udata.udata.buf := idle_space;
  2704.             udata.udata.maxlen := idle_space_size;
  2705.             err := OTLFRcvUData( rawip, udata, flags );
  2706.             if err = noErr then begin
  2707.                 if IsPingResponse( udata.udata.buf, udata.udata.len, remotehost, pmp, ping_len ) then begin
  2708.                     if FindPing( pmp^.id, pmp^.sequence, ted ) & (ted^.result = inProgress) then begin
  2709.                         data_len := Min( ping_len - SizeOf(PingMessage), ted^.results.datasize );
  2710.                         ted^.results.remotehost := remotehost;
  2711.                         Microseconds( finish_time );
  2712.                         ted^.results.timetaken := finish_time.lo - ted^.start_time.lo;
  2713.                         ted^.results.datasize := data_len;
  2714.                         ted^.result := noErr;
  2715.                         BlockMoveData( AddPtrLong( pmp, Sizeof(PingMessage) ), ted^.results.data, data_len );
  2716.                     end;
  2717.                 end;
  2718.             end else if err <> kOTNoDataErr then begin
  2719.                 ClosePing( err );
  2720.             end;
  2721.         end;
  2722.     end;
  2723.     
  2724.     procedure ICMPCompletion (cbp: IPControlBlockPtr; irp:PingRecordPtr);
  2725.         var
  2726.             ted: TransportSendPingDataPtr;
  2727.     begin
  2728.         ted := TransportSendPingDataPtr(irp);
  2729.         ted^.result := cbp^.ioResult;
  2730.         ted^.results.datasize := Min( cbp^.echoinfo.data.size - 8, ted^.results.datasize ); { hack?  -8 to correct MacTCP weirdness???? }
  2731.         BlockMoveData( cbp^.echoinfo.data.buffer, ted^.results.data, ted^.results.datasize );
  2732.         ted^.results.timetaken := (cbp^.echoinfo.echoReplyIn - cbp^.echoinfo.echoRequestOut) * 16667; { ticks -> microseconds }
  2733.     end;
  2734.     
  2735.     function TransportIPSendPing (remotehost: ipAddr; timeout: integer; datap: Ptr; datalen: integer; var token: Ptr): OSStatus;
  2736.         var
  2737.             err: OSStatus;
  2738.             ted: TransportSendPingDataPtr;
  2739.     begin
  2740.         ted := nil;
  2741.         err := OpenTransportSystem;
  2742.         if err = noErr then begin
  2743.             err := MNewPtr( ted, SizeOf(TransportSendPingData) );
  2744.             if err = noErr then begin
  2745.                 ted^.result := inProgress;
  2746.                 ted^.results.remotehost := remotehost;
  2747.                 ted^.timeout := TickCount + timeout*second_in_ticks;
  2748.                 ted^.dead := false;
  2749.                 ted^.results.datasize := datalen + 1000;
  2750.                 err := MNewPtr( ted^.results.data, ted^.results.datasize );
  2751.                 if err = noErr then begin
  2752.                     if have_OT then begin
  2753.                         err := OpenPing;
  2754.                         if err = noErr then begin
  2755.                             ted^.id := ping_id;
  2756.                             ted^.sequence := ping_sequence;
  2757.                             ping_sequence := band(ping_sequence + 1, $7FFF);
  2758.                             err := OTSendPing( remotehost, ted^.id, ted^.sequence, datap, datalen );
  2759.                             if err = noErr then begin
  2760.                                 Microseconds( ted^.start_time );
  2761.                             end;
  2762.                         end;
  2763.                     end else begin
  2764.                         err := MTIPSendPing( remotehost, timeout, datap, datalen, ICMPCompletion, pointer(ted) );
  2765.                     end;
  2766.                 end;
  2767.                 if err <> noErr then begin
  2768.                     MDisposePtr( ted^.results.data );
  2769.                     MDisposePtr( ted );
  2770.                 end else begin
  2771.                     EnquePing( ted );
  2772.                 end;
  2773.             end;
  2774.             token := Ptr(ted);
  2775.         end;
  2776.         TransportIPSendPing := err;
  2777.     end;
  2778.     
  2779.     procedure TransportGetIPSendPingResult( var token: Ptr; var result: OSStatus; var results: TransportPingResults );
  2780.         var
  2781.             ted: TransportSendPingDataPtr;
  2782.     begin
  2783.         if have_OT then begin
  2784.             ReadPingResponse;
  2785.         end;
  2786.         KillDeadPings;
  2787.         ted := TransportSendPingDataPtr(token);
  2788.         if ValidPing( ted ) then begin
  2789.             result := ted^.result;
  2790.             if result <> inProgress then begin
  2791.                 DequePing( ted );
  2792.                 results := ted^.results;
  2793.                 if result <> noErr then begin
  2794.                     MDisposePtr( results.data );
  2795.                 end;
  2796.                 MDisposePtr( token );
  2797.             end;
  2798.         end else begin
  2799.             result := -900021;
  2800.         end;
  2801.     end;
  2802.     
  2803.     procedure TransportDisposeIPSendPingResult( var results: TransportPingResults );
  2804.     begin
  2805.         MDisposePtr( results.data );
  2806.     end;
  2807.     
  2808.     procedure TransportAbortIPSendPing( var token: Ptr );
  2809.         var
  2810.             ted: TransportSendPingDataPtr;
  2811.     begin
  2812.         ted := TransportSendPingDataPtr(token);
  2813.         Assert( ted <> nil );
  2814.         if have_OT then begin
  2815.             if  TransportSystemIsAlive = noErr then begin
  2816.                 KillOTPing( ted );
  2817.             end;
  2818.         end else begin
  2819.             ted^.dead := true;
  2820.         end;
  2821.         token := nil;
  2822.     end;
  2823.     
  2824.     procedure IdleTransports;
  2825.         var
  2826.             this, next:TransportRecordPtr;
  2827.     begin
  2828.         this := TransportRecordPtr(transports.qHead);
  2829.         while this <> nil do begin
  2830.             next := this^.next;
  2831.             ProcessOpen(this);
  2832.             if this^.open_result = noErr then begin
  2833.                 IdleSend(this);
  2834.                 IdleReceive(this);
  2835.             end;
  2836.             if not have_OT then begin
  2837.                 IdleMacTCPConnectionState(this);
  2838.             end;
  2839.             this := next;
  2840.         end;
  2841.     end;
  2842.         
  2843.     procedure IdleTransport;
  2844.     begin
  2845.         IdleDNRs;
  2846.         IdleTransports;
  2847.         ReadPingResponse;
  2848.         CheckClosePing;
  2849.     end;
  2850.     
  2851.     function HasOTLib:boolean;
  2852.     begin
  2853. {$IFC GENERATINGPOWERPC}
  2854.         HasOTLib := longint(@OTInstallNotifier) <> kUnresolvedCFragSymbolAddress;
  2855. {$ELSEC}
  2856.         HasOTLib := true;
  2857. {$ENDC}
  2858.     end;
  2859.  
  2860.     function HasOT: boolean;
  2861.         var
  2862.             gv: longint;
  2863.     begin
  2864.         HasOT := HasOTLib & (Gestalt(gestaltOpenTpt, gv) = noErr) & 
  2865.             btst(gv, gestaltOpenTptPresentBit) & btst(gv, gestaltOpenTptTCPPresentBit);
  2866.     end;
  2867.  
  2868.     procedure ConfigureTransport(allow_OT: Boolean);
  2869.     begin
  2870.         DidStartup( startup_check );
  2871.         StartupTransport;
  2872.         if not allow_OT then begin
  2873.             have_OT := false;
  2874.         end else begin
  2875.             have_OT := HasOT;
  2876.         end;
  2877.     end;
  2878.     
  2879.     function InitTransport(var msg: integer):OSStatus;
  2880.         var
  2881.             err: OSErr;
  2882.     begin
  2883. {$unused(msg)}
  2884.         AssertDidStartup( startup_check );
  2885. {        transition_notifier_count := 0; } { initialized to zero by default, InstallNotifer may be called before Startup() }
  2886.         hack_MemoryReleasedProc := nil;
  2887.         gMyDeferredTaskHandlerProc := NewProc(@MyDeferredTaskHandler, uppDeferredTaskProcInfo);
  2888.         tcp_open_status := -900022;
  2889.         transport_system_is_alive := false;
  2890.         last_reopen_time := TickCount - max_reopen_frequency - 10;
  2891.         dnrs.qHead := nil;
  2892.         dnrs.qTail := nil;
  2893.         transports.qHead := nil;
  2894.         transports.qTail := nil;
  2895.         is_ref := nil;
  2896.         is_result := -900025;
  2897.         err := MNewPtr( idle_space, idle_space_size );
  2898.         if err = noErr then begin
  2899.             InitPing;
  2900.         end;
  2901.         InstallTransitionNotifier( DNRNotifier, true );
  2902.         ot_version := 0;
  2903.         if have_OT then begin
  2904.             AddOSErr( err, Gestalt( gestaltOpenTptVersions, ot_version ) );
  2905.             InstallTransitionNotifier( PingNotifier, true );
  2906.             InstallTransitionNotifier( InternetServicesNotifier, true );
  2907.         end;
  2908.         InitTransport := err;
  2909.     end;
  2910.     
  2911.     procedure FinishTransport;
  2912.     begin
  2913.         CloseTransportSystem;
  2914.     end;
  2915.     
  2916.     procedure StartupTransport;
  2917.     begin
  2918.         StartupTCPUtils;
  2919.         SetStartup(InitTransport, IdleTransport, 0, FinishTransport);
  2920.     end;
  2921.     
  2922. end.
  2923.  
  2924.  
  2925.